]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'pm/linux-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 00:43:41 +0000 (11:43 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 00:43:44 +0000 (11:43 +1100)
176 files changed:
Documentation/ABI/testing/sysfs-power
Documentation/kernel-parameters.txt
arch/arm/kernel/time.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-mediatek/mediatek.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-rockchip/rockchip.c
arch/arm/mach-shmobile/setup-r8a7779.c
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-spear/spear13xx.c
arch/arm/mach-sunxi/sunxi.c
arch/arm/mach-u300/core.c
arch/arm/mach-ux500/timer.c
arch/arm/mach-zynq/common.c
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/irq.h
arch/arm64/kernel/acpi.c
arch/arm64/kernel/time.c
arch/ia64/include/asm/pci.h
arch/ia64/pci/pci.c
arch/microblaze/kernel/setup.c
arch/mips/pistachio/time.c
arch/mips/ralink/clk.c
arch/nios2/kernel/time.c
arch/x86/include/asm/msr-index.h
arch/x86/kernel/acpi/boot.c
arch/x86/pci/acpi.c
arch/xtensa/kernel/time.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_pad.c
drivers/acpi/acpi_pnp.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acapps.h
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acopcode.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/dbcmds.c [new file with mode: 0644]
drivers/acpi/acpica/dbconvert.c [new file with mode: 0644]
drivers/acpi/acpica/dbdisply.c [new file with mode: 0644]
drivers/acpi/acpica/dbexec.c [new file with mode: 0644]
drivers/acpi/acpica/dbfileio.c [new file with mode: 0644]
drivers/acpi/acpica/dbhistry.c [new file with mode: 0644]
drivers/acpi/acpica/dbinput.c [new file with mode: 0644]
drivers/acpi/acpica/dbmethod.c [new file with mode: 0644]
drivers/acpi/acpica/dbnames.c [new file with mode: 0644]
drivers/acpi/acpica/dbobject.c [new file with mode: 0644]
drivers/acpi/acpica/dbstats.c [new file with mode: 0644]
drivers/acpi/acpica/dbtest.c [new file with mode: 0644]
drivers/acpi/acpica/dbutils.c [new file with mode: 0644]
drivers/acpi/acpica/dbxface.c [new file with mode: 0644]
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psutils.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/utdecode.c
drivers/acpi/acpica/utfileio.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utxface.c
drivers/acpi/cppc_acpi.c [new file with mode: 0644]
drivers/acpi/device_pm.c
drivers/acpi/device_sysfs.c
drivers/acpi/ec.c
drivers/acpi/glue.c
drivers/acpi/internal.h
drivers/acpi/nfit.c
drivers/acpi/nfit.h
drivers/acpi/osl.c
drivers/acpi/pci_root.c
drivers/acpi/proc.c
drivers/acpi/processor_driver.c
drivers/acpi/property.c
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/tables.c
drivers/acpi/video_detect.c
drivers/base/power/Makefile
drivers/base/power/clock_ops.c
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/base/power/generic_ops.c
drivers/base/power/opp/Makefile [new file with mode: 0644]
drivers/base/power/opp/core.c [moved from drivers/base/power/opp.c with 79% similarity]
drivers/base/power/opp/cpu.c [new file with mode: 0644]
drivers/base/power/opp/opp.h [new file with mode: 0644]
drivers/base/power/wakeup.c
drivers/base/property.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/clksrc-probe.c [moved from drivers/clocksource/clksrc-of.c with 91% similarity]
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/Makefile
drivers/cpufreq/arm_big_little.h
drivers/cpufreq/arm_big_little_dt.c
drivers/cpufreq/cppc_cpufreq.c [new file with mode: 0644]
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_opp.c [deleted file]
drivers/cpufreq/exynos5440-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/integrator-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/mt8173-cpufreq.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/tegra20-cpufreq.c
drivers/cpuidle/cpuidle-mvebu-v7.c
drivers/dma/acpi-dma.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/input/serio/i8042.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irqchip.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pnp/pnpacpi/core.c
drivers/power/avs/rockchip-io-domain.c
drivers/powercap/intel_rapl.c
drivers/soc/dove/pmu.c
include/acpi/acexcep.h
include/acpi/acpi_bus.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/actbl1.h
include/acpi/cppc_acpi.h [new file with mode: 0644]
include/acpi/platform/acenv.h
include/acpi/platform/aclinux.h
include/acpi/platform/aclinuxex.h
include/acpi/processor.h
include/asm-generic/vmlinux.lds.h
include/linux/acpi.h
include/linux/acpi_irq.h [deleted file]
include/linux/clocksource.h
include/linux/cpufreq.h
include/linux/fwnode.h
include/linux/ioport.h
include/linux/irqchip.h
include/linux/irqchip/arm-gic-acpi.h [deleted file]
include/linux/pci-acpi.h
include/linux/pm.h
include/linux/pm_domain.h
include/linux/pm_opp.h
include/linux/property.h
include/linux/suspend.h
kernel/irq/pm.c
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/suspend.c
tools/power/acpi/tools/acpidump/apfiles.c

index f4551816329e17ae8020a256211b499776c19e4b..50b368d490b599f29809e55bbdd0a29535163fa4 100644 (file)
@@ -256,3 +256,15 @@ Description:
                Writing a "1" enables this printing while writing a "0"
                disables it.  The default value is "0".  Reading from this file
                will display the current value.
+
+What:          /sys/power/pm_wakeup_irq
+Date:          April 2015
+Contact:       Alexandra Yates <alexandra.yates@linux.intel.org>
+Description:
+               The /sys/power/pm_wakeup_irq file reports to user space the IRQ
+               number of the first wakeup interrupt (that is, the first
+               interrupt from an IRQ line armed for system wakeup) seen by the
+               kernel during the most recent system suspend/resume cycle.
+
+               This output is useful for system wakeup diagnostics of spurious
+               wakeup interrupts.
index 046832ef14ce136d4192e6cf7b39fb54de75c522..c76200afb7bb6575402427786decd10ce072dc7d 100644 (file)
@@ -167,7 +167,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        acpi=           [HW,ACPI,X86,ARM64]
                        Advanced Configuration and Power Interface
-                       Format: { force | off | strict | noirq | rsdt }
+                       Format: { force | off | strict | noirq | rsdt |
+                                 copy_dsdt }
                        force -- enable ACPI if default was off
                        off -- disable ACPI if default was on
                        noirq -- do not use ACPI for IRQ routing
@@ -1561,6 +1562,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                hwp_only
                        Only load intel_pstate on systems which support
                        hardware P state control (HWP) if available.
+               no_acpi
+                       Don't use ACPI processor performance control objects
+                       _PSS and _PPC specified limits.
 
        intremap=       [X86-64, Intel-IOMMU]
                        on      enable Interrupt Remapping (default)
index a66e37e211a9a8cbfabf85d9213f6b73db417085..97b22fa7cb3a62d5d6fd4a36935d4a32715fe6cf 100644 (file)
@@ -120,6 +120,6 @@ void __init time_init(void)
 #ifdef CONFIG_COMMON_CLK
                of_clk_init(NULL);
 #endif
-               clocksource_of_init();
+               clocksource_probe();
        }
 }
index 9602cc12d2f1014efbac3887dc49278191745c67..3878494bd11827756150235f404e86cb520a14a0 100644 (file)
@@ -350,7 +350,7 @@ static void __init imx6q_opp_init(void)
                return;
        }
 
-       if (of_init_opp_table(cpu_dev)) {
+       if (dev_pm_opp_of_add_table(cpu_dev)) {
                pr_warn("failed to init OPP table\n");
                goto put_node;
        }
index 19dc738c1abc5ab340d640c59a0ecccaa2f88aa5..d019a080a559a467acd503c94c0f70ec7c0050af 100644 (file)
@@ -40,7 +40,7 @@ static void __init mediatek_timer_init(void)
        }
 
        of_clk_init(NULL);
-       clocksource_of_init();
+       clocksource_probe();
 };
 
 static const char * const mediatek_board_dt_compat[] = {
index 05c17eb2f2d9374122bdecffcd163931f2ab251c..b18ebbefae09577e20b19e53167aca5ef11b8d86 100644 (file)
@@ -491,7 +491,7 @@ void __init omap_init_time(void)
                        2, "timer_sys_ck", NULL, false);
 
        if (of_have_populated_dt())
-               clocksource_of_init();
+               clocksource_probe();
 }
 
 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX)
@@ -521,7 +521,7 @@ static void __init omap4_sync32k_timer_init(void)
 void __init omap4_local_timer_init(void)
 {
        omap4_sync32k_timer_init();
-       clocksource_of_init();
+       clocksource_probe();
 }
 #endif
 
@@ -645,7 +645,7 @@ void __init omap5_realtime_timer_init(void)
        omap4_sync32k_timer_init();
        realtime_counter_init();
 
-       clocksource_of_init();
+       clocksource_probe();
 }
 #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */
 
index b6cf3b449428960d28590f5cdad6e331d2239080..251c7b9c5f9b6c15ffdab39475d6b7764e9c2fc0 100644 (file)
@@ -67,7 +67,7 @@ static void __init rockchip_timer_init(void)
        }
 
        of_clk_init(NULL);
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 static void __init rockchip_dt_init(void)
index 6bfa6407a27c0baed01a04c17f223b0e6087c5cf..1e572a903f8e470e8864738be0464b3a48b63940 100644 (file)
@@ -97,7 +97,7 @@ static u32 __init r8a7779_read_mode_pins(void)
 static void __init r8a7779_init_time(void)
 {
        r8a7779_clocks_init(r8a7779_read_mode_pins());
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 static const char *const r8a7779_compat_dt[] __initconst = {
index aa3339258d9c0232a4092a01e9abf2b3243098f6..9eccde3c7b137151e3fcff5c882cb6bd62870195 100644 (file)
@@ -128,7 +128,7 @@ void __init rcar_gen2_timer_init(void)
 #endif /* CONFIG_ARM_ARCH_TIMER */
 
        rcar_gen2_clocks_init(mode);
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 struct memory_reserve_config {
index b7afce6795f436e9259e84d34f01fa246173eedf..ca2f6a82a4141e7d448779901e2fc1a151d118b8 100644 (file)
@@ -124,5 +124,5 @@ void __init spear13xx_timer_init(void)
        clk_put(pclk);
 
        spear_setup_of_timer();
-       clocksource_of_init();
+       clocksource_probe();
 }
index 8583a9ca86bd6f70220c4055fb9da8b916a7233a..c2be98f38e73b2006ea664b7089dc427a2575d8e 100644 (file)
@@ -47,7 +47,7 @@ static void __init sun6i_timer_init(void)
        of_clk_init(NULL);
        if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
                sun6i_reset_init();
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family")
index 35670b15f28182299a94373cfd8fdae54c2f7e2f..546338bbacf8670b30b483c1c69737bc5813a723 100644 (file)
@@ -408,7 +408,7 @@ static const char * u300_board_compat[] = {
 DT_MACHINE_START(U300_DT, "U300 S335/B335 (Device Tree)")
        .map_io         = u300_map_io,
        .init_irq       = u300_init_irq_dt,
-       .init_time      = clocksource_of_init,
+       .init_time      = clocksource_probe,
        .init_machine   = u300_init_machine_dt,
        .restart        = u300_restart,
        .dt_compat      = u300_board_compat,
index ff28d8ad1ed7347dec1928ca0d2bb1ac118d7c47..8d2d233f8e6cfaa248801c69033b511d7adef5af 100644 (file)
@@ -44,5 +44,5 @@ void __init ux500_timer_init(void)
 
 dt_fail:
        clksrc_dbx500_prcmu_init(prcmu_timer_base);
-       clocksource_of_init();
+       clocksource_probe();
 }
index 5a6e4e20ca0a98ae07d39d6b764d2f799fc1448d..6f39d03cc27eac777a243abcb5a08ea4c35e8d7c 100644 (file)
@@ -154,7 +154,7 @@ static void __init zynq_timer_init(void)
 
        zynq_clock_init();
        of_clk_init(NULL);
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 static struct map_desc zynq_cortex_a9_scu_map __initdata = {
index 5f8a38dee2744d6655bb6eceb3cabf6917c80ad4..caafd63b8092d8102401112d811b1055f4cc3524 100644 (file)
@@ -12,7 +12,6 @@
 #ifndef _ASM_ACPI_H
 #define _ASM_ACPI_H
 
-#include <linux/irqchip/arm-gic-acpi.h>
 #include <linux/mm.h>
 #include <linux/psci.h>
 
index 09169296c3cc4c235d10a0b040c68938eb4a4c80..23eb450b820ba03ce83b737f308fcd3d6b33f9a8 100644 (file)
@@ -1,23 +1,10 @@
 #ifndef __ASM_IRQ_H
 #define __ASM_IRQ_H
 
-#include <linux/irqchip/arm-gic-acpi.h>
-
 #include <asm-generic/irq.h>
 
 struct pt_regs;
 
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
-static inline void acpi_irq_init(void)
-{
-       /*
-        * Hardcode ACPI IRQ chip initialization to GICv2 for now.
-        * Proper irqchip infrastructure will be implemented along with
-        * incoming  GICv2m|GICv3|ITS bits.
-        */
-       acpi_gic_init();
-}
-#define acpi_irq_init acpi_irq_init
-
 #endif
index 137d537ddceb8001f15d9daa18c95631b561a085..d1ce8e2f98b99bcb1fba0bae25c08e8f851c4f4b 100644 (file)
@@ -211,31 +211,6 @@ void __init acpi_boot_table_init(void)
        }
 }
 
-void __init acpi_gic_init(void)
-{
-       struct acpi_table_header *table;
-       acpi_status status;
-       acpi_size tbl_size;
-       int err;
-
-       if (acpi_disabled)
-               return;
-
-       status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
-       if (ACPI_FAILURE(status)) {
-               const char *msg = acpi_format_exception(status);
-
-               pr_err("Failed to get MADT table, %s\n", msg);
-               return;
-       }
-
-       err = gic_v2_acpi_init(table);
-       if (err)
-               pr_err("Failed to initialize GIC IRQ controller");
-
-       early_acpi_os_unmap_memory((char *)table, tbl_size);
-}
-
 #ifdef CONFIG_ACPI_APEI
 pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
 {
index 149151fb42bb1579127100f24a0f91a2124c92e1..13339b6ffc1a07839103fca328f1eccd6d185c12 100644 (file)
@@ -67,16 +67,10 @@ void __init time_init(void)
        u32 arch_timer_rate;
 
        of_clk_init(NULL);
-       clocksource_of_init();
+       clocksource_probe();
 
        tick_setup_hrtimer_broadcast();
 
-       /*
-        * Since ACPI or FDT will only one be available in the system,
-        * we can use acpi_generic_timer_init() here safely
-        */
-       acpi_generic_timer_init();
-
        arch_timer_rate = arch_timer_get_rate();
        if (!arch_timer_rate)
                panic("Unable to initialise architected timer.\n");
index 36d2c1e3928bc744eb2d66eeb18aa7291969eab5..07039d168f37bfd14048e9e4a73d50bc4d20f35d 100644 (file)
@@ -64,11 +64,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
 #define pci_legacy_read platform_pci_legacy_read
 #define pci_legacy_write platform_pci_legacy_write
 
-struct iospace_resource {
-       struct list_head list;
-       struct resource res;
-};
-
 struct pci_controller {
        struct acpi_device *companion;
        void *iommu;
index 7cc3be9fa7c65a0dd700dfd30c04cc7be822922d..8f6ac2f8ae4c8cebea5cd85d79b11251d7b09979 100644 (file)
@@ -115,33 +115,13 @@ struct pci_ops pci_root_ops = {
        .write = pci_write,
 };
 
-/* Called by ACPI when it finds a new root bus.  */
-
-static struct pci_controller *alloc_pci_controller(int seg)
-{
-       struct pci_controller *controller;
-
-       controller = kzalloc(sizeof(*controller), GFP_KERNEL);
-       if (!controller)
-               return NULL;
-
-       controller->segment = seg;
-       return controller;
-}
-
 struct pci_root_info {
-       struct acpi_device *bridge;
-       struct pci_controller *controller;
-       struct list_head resources;
-       struct resource *res;
-       resource_size_t *res_offset;
-       unsigned int res_num;
+       struct acpi_pci_root_info common;
+       struct pci_controller controller;
        struct list_head io_resources;
-       char *name;
 };
 
-static unsigned int
-new_space (u64 phys_base, int sparse)
+static unsigned int new_space(u64 phys_base, int sparse)
 {
        u64 mmio_base;
        int i;
@@ -168,39 +148,36 @@ new_space (u64 phys_base, int sparse)
        return i;
 }
 
-static u64 add_io_space(struct pci_root_info *info,
-                       struct acpi_resource_address64 *addr)
+static int add_io_space(struct device *dev, struct pci_root_info *info,
+                       struct resource_entry *entry)
 {
-       struct iospace_resource *iospace;
-       struct resource *resource;
+       struct resource_entry *iospace;
+       struct resource *resource, *res = entry->res;
        char *name;
        unsigned long base, min, max, base_port;
        unsigned int sparse = 0, space_nr, len;
 
-       len = strlen(info->name) + 32;
-       iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL);
+       len = strlen(info->common.name) + 32;
+       iospace = resource_list_create_entry(NULL, len);
        if (!iospace) {
-               dev_err(&info->bridge->dev,
-                               "PCI: No memory for %s I/O port space\n",
-                               info->name);
-               goto out;
+               dev_err(dev, "PCI: No memory for %s I/O port space\n",
+                       info->common.name);
+               return -ENOMEM;
        }
 
-       name = (char *)(iospace + 1);
-
-       min = addr->address.minimum;
-       max = min + addr->address.address_length - 1;
-       if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION)
+       if (res->flags & IORESOURCE_IO_SPARSE)
                sparse = 1;
-
-       space_nr = new_space(addr->address.translation_offset, sparse);
+       space_nr = new_space(entry->offset, sparse);
        if (space_nr == ~0)
                goto free_resource;
 
+       name = (char *)(iospace + 1);
+       min = res->start - entry->offset;
+       max = res->end - entry->offset;
        base = __pa(io_space[space_nr].mmio_base);
        base_port = IO_SPACE_BASE(space_nr);
-       snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
-               base_port + min, base_port + max);
+       snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name,
+                base_port + min, base_port + max);
 
        /*
         * The SDM guarantees the legacy 0-64K space is sparse, but if the
@@ -210,270 +187,125 @@ static u64 add_io_space(struct pci_root_info *info,
        if (space_nr == 0)
                sparse = 1;
 
-       resource = &iospace->res;
+       resource = iospace->res;
        resource->name  = name;
        resource->flags = IORESOURCE_MEM;
        resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
        resource->end   = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
        if (insert_resource(&iomem_resource, resource)) {
-               dev_err(&info->bridge->dev,
-                               "can't allocate host bridge io space resource  %pR\n",
-                               resource);
+               dev_err(dev,
+                       "can't allocate host bridge io space resource  %pR\n",
+                       resource);
                goto free_resource;
        }
 
-       list_add_tail(&iospace->list, &info->io_resources);
-       return base_port;
+       entry->offset = base_port;
+       res->start = min + base_port;
+       res->end = max + base_port;
+       resource_list_add_tail(iospace, &info->io_resources);
 
-free_resource:
-       kfree(iospace);
-out:
-       return ~0;
-}
-
-static acpi_status resource_to_window(struct acpi_resource *resource,
-                                     struct acpi_resource_address64 *addr)
-{
-       acpi_status status;
+       return 0;
 
-       /*
-        * We're only interested in _CRS descriptors that are
-        *      - address space descriptors for memory or I/O space
-        *      - non-zero size
-        */
-       status = acpi_resource_to_address64(resource, addr);
-       if (ACPI_SUCCESS(status) &&
-           (addr->resource_type == ACPI_MEMORY_RANGE ||
-            addr->resource_type == ACPI_IO_RANGE) &&
-           addr->address.address_length)
-               return AE_OK;
-
-       return AE_ERROR;
+free_resource:
+       resource_list_free_entry(iospace);
+       return -ENOSPC;
 }
 
-static acpi_status count_window(struct acpi_resource *resource, void *data)
+/*
+ * An IO port or MMIO resource assigned to a PCI host bridge may be
+ * consumed by the host bridge itself or available to its child
+ * bus/devices. The ACPI specification defines a bit (Producer/Consumer)
+ * to tell whether the resource is consumed by the host bridge itself,
+ * but firmware hasn't used that bit consistently, so we can't rely on it.
+ *
+ * On x86 and IA64 platforms, all IO port and MMIO resources are assumed
+ * to be available to child bus/devices except one special case:
+ *     IO port [0xCF8-0xCFF] is consumed by the host bridge itself
+ *     to access PCI configuration space.
+ *
+ * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF].
+ */
+static bool resource_is_pcicfg_ioport(struct resource *res)
 {
-       unsigned int *windows = (unsigned int *) data;
-       struct acpi_resource_address64 addr;
-       acpi_status status;
-
-       status = resource_to_window(resource, &addr);
-       if (ACPI_SUCCESS(status))
-               (*windows)++;
-
-       return AE_OK;
+       return (res->flags & IORESOURCE_IO) &&
+               res->start == 0xCF8 && res->end == 0xCFF;
 }
 
-static acpi_status add_window(struct acpi_resource *res, void *data)
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
 {
-       struct pci_root_info *info = data;
-       struct resource *resource;
-       struct acpi_resource_address64 addr;
-       acpi_status status;
-       unsigned long flags, offset = 0;
-       struct resource *root;
-
-       /* Return AE_OK for non-window resources to keep scanning for more */
-       status = resource_to_window(res, &addr);
-       if (!ACPI_SUCCESS(status))
-               return AE_OK;
-
-       if (addr.resource_type == ACPI_MEMORY_RANGE) {
-               flags = IORESOURCE_MEM;
-               root = &iomem_resource;
-               offset = addr.address.translation_offset;
-       } else if (addr.resource_type == ACPI_IO_RANGE) {
-               flags = IORESOURCE_IO;
-               root = &ioport_resource;
-               offset = add_io_space(info, &addr);
-               if (offset == ~0)
-                       return AE_OK;
-       } else
-               return AE_OK;
-
-       resource = &info->res[info->res_num];
-       resource->name = info->name;
-       resource->flags = flags;
-       resource->start = addr.address.minimum + offset;
-       resource->end = resource->start + addr.address.address_length - 1;
-       info->res_offset[info->res_num] = offset;
-
-       if (insert_resource(root, resource)) {
-               dev_err(&info->bridge->dev,
-                       "can't allocate host bridge window %pR\n",
-                       resource);
-       } else {
-               if (offset)
-                       dev_info(&info->bridge->dev, "host bridge window %pR "
-                                "(PCI address [%#llx-%#llx])\n",
-                                resource,
-                                resource->start - offset,
-                                resource->end - offset);
-               else
-                       dev_info(&info->bridge->dev,
-                                "host bridge window %pR\n", resource);
+       struct device *dev = &ci->bridge->dev;
+       struct pci_root_info *info;
+       struct resource *res;
+       struct resource_entry *entry, *tmp;
+       int status;
+
+       status = acpi_pci_probe_root_resources(ci);
+       if (status > 0) {
+               info = container_of(ci, struct pci_root_info, common);
+               resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+                       res = entry->res;
+                       if (res->flags & IORESOURCE_MEM) {
+                               /*
+                                * HP's firmware has a hack to work around a
+                                * Windows bug. Ignore these tiny memory ranges.
+                                */
+                               if (resource_size(res) <= 16) {
+                                       resource_list_del(entry);
+                                       insert_resource(&iomem_resource,
+                                                       entry->res);
+                                       resource_list_add_tail(entry,
+                                                       &info->io_resources);
+                               }
+                       } else if (res->flags & IORESOURCE_IO) {
+                               if (resource_is_pcicfg_ioport(entry->res))
+                                       resource_list_destroy_entry(entry);
+                               else if (add_io_space(dev, info, entry))
+                                       resource_list_destroy_entry(entry);
+                       }
+               }
        }
-       /* HP's firmware has a hack to work around a Windows bug.
-        * Ignore these tiny memory ranges */
-       if (!((resource->flags & IORESOURCE_MEM) &&
-             (resource->end - resource->start < 16)))
-               pci_add_resource_offset(&info->resources, resource,
-                                       info->res_offset[info->res_num]);
-
-       info->res_num++;
-       return AE_OK;
-}
 
-static void free_pci_root_info_res(struct pci_root_info *info)
-{
-       struct iospace_resource *iospace, *tmp;
-
-       list_for_each_entry_safe(iospace, tmp, &info->io_resources, list)
-               kfree(iospace);
-
-       kfree(info->name);
-       kfree(info->res);
-       info->res = NULL;
-       kfree(info->res_offset);
-       info->res_offset = NULL;
-       info->res_num = 0;
-       kfree(info->controller);
-       info->controller = NULL;
+       return status;
 }
 
-static void __release_pci_root_info(struct pci_root_info *info)
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
 {
-       int i;
-       struct resource *res;
-       struct iospace_resource *iospace;
+       struct pci_root_info *info;
+       struct resource_entry *entry, *tmp;
 
-       list_for_each_entry(iospace, &info->io_resources, list)
-               release_resource(&iospace->res);
-
-       for (i = 0; i < info->res_num; i++) {
-               res = &info->res[i];
-
-               if (!res->parent)
-                       continue;
-
-               if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
-                       continue;
-
-               release_resource(res);
+       info = container_of(ci, struct pci_root_info, common);
+       resource_list_for_each_entry_safe(entry, tmp, &info->io_resources) {
+               release_resource(entry->res);
+               resource_list_destroy_entry(entry);
        }
-
-       free_pci_root_info_res(info);
        kfree(info);
 }
 
-static void release_pci_root_info(struct pci_host_bridge *bridge)
-{
-       struct pci_root_info *info = bridge->release_data;
-
-       __release_pci_root_info(info);
-}
-
-static int
-probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
-               int busnum, int domain)
-{
-       char *name;
-
-       name = kmalloc(16, GFP_KERNEL);
-       if (!name)
-               return -ENOMEM;
-
-       sprintf(name, "PCI Bus %04x:%02x", domain, busnum);
-       info->bridge = device;
-       info->name = name;
-
-       acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
-                       &info->res_num);
-       if (info->res_num) {
-               info->res =
-                       kzalloc_node(sizeof(*info->res) * info->res_num,
-                                    GFP_KERNEL, info->controller->node);
-               if (!info->res) {
-                       kfree(name);
-                       return -ENOMEM;
-               }
-
-               info->res_offset =
-                       kzalloc_node(sizeof(*info->res_offset) * info->res_num,
-                                       GFP_KERNEL, info->controller->node);
-               if (!info->res_offset) {
-                       kfree(name);
-                       kfree(info->res);
-                       info->res = NULL;
-                       return -ENOMEM;
-               }
-
-               info->res_num = 0;
-               acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                       add_window, info);
-       } else
-               kfree(name);
-
-       return 0;
-}
+static struct acpi_pci_root_ops pci_acpi_root_ops = {
+       .pci_ops = &pci_root_ops,
+       .release_info = pci_acpi_root_release_info,
+       .prepare_resources = pci_acpi_root_prepare_resources,
+};
 
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
        struct acpi_device *device = root->device;
-       int domain = root->segment;
-       int bus = root->secondary.start;
-       struct pci_controller *controller;
-       struct pci_root_info *info = NULL;
-       int busnum = root->secondary.start;
-       struct pci_bus *pbus;
-       int ret;
-
-       controller = alloc_pci_controller(domain);
-       if (!controller)
-               return NULL;
-
-       controller->companion = device;
-       controller->node = acpi_get_node(device->handle);
+       struct pci_root_info *info;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
                dev_err(&device->dev,
-                               "pci_bus %04x:%02x: ignored (out of memory)\n",
-                               domain, busnum);
-               kfree(controller);
+                       "pci_bus %04x:%02x: ignored (out of memory)\n",
+                       root->segment, (int)root->secondary.start);
                return NULL;
        }
 
-       info->controller = controller;
+       info->controller.segment = root->segment;
+       info->controller.companion = device;
+       info->controller.node = acpi_get_node(device->handle);
        INIT_LIST_HEAD(&info->io_resources);
-       INIT_LIST_HEAD(&info->resources);
-
-       ret = probe_pci_root_info(info, device, busnum, domain);
-       if (ret) {
-               kfree(info->controller);
-               kfree(info);
-               return NULL;
-       }
-       /* insert busn resource at first */
-       pci_add_resource(&info->resources, &root->secondary);
-       /*
-        * See arch/x86/pci/acpi.c.
-        * The desired pci bus might already be scanned in a quirk. We
-        * should handle the case here, but it appears that IA64 hasn't
-        * such quirk. So we just ignore the case now.
-        */
-       pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
-                                  &info->resources);
-       if (!pbus) {
-               pci_free_resource_list(&info->resources);
-               __release_pci_root_info(info);
-               return NULL;
-       }
-
-       pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge),
-                       release_pci_root_info, info);
-       pci_scan_child_bus(pbus);
-       return pbus;
+       return acpi_pci_root_create(root, &pci_acpi_root_ops,
+                                   &info->common, &info->controller);
 }
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
index ab5b488e1fde666bc24b3dd3d78f6f4950829282..89a2a93949274b16b3508b314d0cbdf6db5946e6 100644 (file)
@@ -194,7 +194,7 @@ void __init time_init(void)
 {
        of_clk_init(NULL);
        setup_cpuinfo_clk();
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 #ifdef CONFIG_DEBUG_FS
index 8a377346f0cabbf5ce91199ca039ec013b16dda1..1022201b2bebddf5453cda975ab6820bd432e41c 100644 (file)
@@ -39,7 +39,7 @@ void __init plat_time_init(void)
        struct clk *clk;
 
        of_clk_init(NULL);
-       clocksource_of_init();
+       clocksource_probe();
 
        np = of_get_cpu_node(0, NULL);
        if (!np) {
index feb5a9bf98b4bc316a8e568635613e02fd262b68..25c4a61779f1f3a015b9eb7d76bdfc63e3a7dab4 100644 (file)
@@ -75,5 +75,5 @@ void __init plat_time_init(void)
        pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
        mips_hpt_frequency = clk_get_rate(clk) / 2;
        clk_put(clk);
-       clocksource_of_init();
+       clocksource_probe();
 }
index bbc3f9157f9c4fec3418e8a92c20f204924e0c5b..e835dda2bfe2d5342f0b87f763476ebd9ae81875 100644 (file)
@@ -324,7 +324,7 @@ void __init time_init(void)
        if (count < 2)
                panic("%d timer is found, it needs 2 timers in system\n", count);
 
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init);
index b8c14bb7fc8f37ee004dc10342a99c8579110e1d..9f3905697f123200eb1f7ecc749239dc5d5e1b2d 100644 (file)
 #define MSR_GFX_PERF_LIMIT_REASONS     0x000006B0
 #define MSR_RING_PERF_LIMIT_REASONS    0x000006B1
 
+/* Config TDP MSRs */
+#define MSR_CONFIG_TDP_NOMINAL         0x00000648
+#define MSR_CONFIG_TDP_LEVEL1          0x00000649
+#define MSR_CONFIG_TDP_LEVEL2          0x0000064A
+#define MSR_CONFIG_TDP_CONTROL         0x0000064B
+#define MSR_TURBO_ACTIVATION_RATIO     0x0000064C
+
 /* Hardware P state interface */
 #define MSR_PPERF                      0x0000064e
 #define MSR_PERF_LIMIT_REASONS         0x0000064f
index ded848c20e05a115a3556b95cd4a8d6b30c0bdbe..e75907601a41c349e05c8dfe63047dc460ccdf30 100644 (file)
@@ -976,6 +976,8 @@ static int __init acpi_parse_madt_lapic_entries(void)
 {
        int count;
        int x2count = 0;
+       int ret;
+       struct acpi_subtable_proc madt_proc[2];
 
        if (!cpu_has_apic)
                return -ENODEV;
@@ -999,10 +1001,22 @@ static int __init acpi_parse_madt_lapic_entries(void)
                                      acpi_parse_sapic, MAX_LOCAL_APIC);
 
        if (!count) {
-               x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC,
-                                       acpi_parse_x2apic, MAX_LOCAL_APIC);
-               count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC,
-                                       acpi_parse_lapic, MAX_LOCAL_APIC);
+               memset(madt_proc, 0, sizeof(madt_proc));
+               madt_proc[0].id = ACPI_MADT_TYPE_LOCAL_APIC;
+               madt_proc[0].handler = acpi_parse_lapic;
+               madt_proc[1].id = ACPI_MADT_TYPE_LOCAL_X2APIC;
+               madt_proc[1].handler = acpi_parse_x2apic;
+               ret = acpi_table_parse_entries_array(ACPI_SIG_MADT,
+                               sizeof(struct acpi_table_madt),
+                               madt_proc, ARRAY_SIZE(madt_proc), MAX_LOCAL_APIC);
+               if (ret < 0) {
+                       printk(KERN_ERR PREFIX
+                                       "Error parsing LAPIC/X2APIC entries\n");
+                       return ret;
+               }
+
+               x2count = madt_proc[0].count;
+               count = madt_proc[1].count;
        }
        if (!count && !x2count) {
                printk(KERN_ERR PREFIX "No LAPIC entries present\n");
index ff9911707160ac7691e119aad62f32d7f61c143a..3cd69832d7f4c6f3743bbb3a190c39672c89461d 100644 (file)
@@ -4,16 +4,15 @@
 #include <linux/irq.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/pci-acpi.h>
 #include <asm/numa.h>
 #include <asm/pci_x86.h>
 
 struct pci_root_info {
-       struct acpi_device *bridge;
-       char name[16];
+       struct acpi_pci_root_info common;
        struct pci_sysdata sd;
 #ifdef CONFIG_PCI_MMCONFIG
        bool mcfg_added;
-       u16 segment;
        u8 start_bus;
        u8 end_bus;
 #endif
@@ -178,15 +177,18 @@ static int check_segment(u16 seg, struct device *dev, char *estr)
        return 0;
 }
 
-static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
-                         u8 end, phys_addr_t addr)
+static int setup_mcfg_map(struct acpi_pci_root_info *ci)
 {
-       int result;
-       struct device *dev = &info->bridge->dev;
+       int result, seg;
+       struct pci_root_info *info;
+       struct acpi_pci_root *root = ci->root;
+       struct device *dev = &ci->bridge->dev;
 
-       info->start_bus = start;
-       info->end_bus = end;
+       info = container_of(ci, struct pci_root_info, common);
+       info->start_bus = (u8)root->secondary.start;
+       info->end_bus = (u8)root->secondary.end;
        info->mcfg_added = false;
+       seg = info->sd.domain;
 
        /* return success if MMCFG is not in use */
        if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
@@ -195,7 +197,8 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
        if (!(pci_probe & PCI_PROBE_MMCONF))
                return check_segment(seg, dev, "MMCONFIG is disabled,");
 
-       result = pci_mmconfig_insert(dev, seg, start, end, addr);
+       result = pci_mmconfig_insert(dev, seg, info->start_bus, info->end_bus,
+                                    root->mcfg_addr);
        if (result == 0) {
                /* enable MMCFG if it hasn't been enabled yet */
                if (raw_pci_ext_ops == NULL)
@@ -208,134 +211,55 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
        return 0;
 }
 
-static void teardown_mcfg_map(struct pci_root_info *info)
+static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
 {
+       struct pci_root_info *info;
+
+       info = container_of(ci, struct pci_root_info, common);
        if (info->mcfg_added) {
-               pci_mmconfig_delete(info->segment, info->start_bus,
-                                   info->end_bus);
+               pci_mmconfig_delete(info->sd.domain,
+                                   info->start_bus, info->end_bus);
                info->mcfg_added = false;
        }
 }
 #else
-static int setup_mcfg_map(struct pci_root_info *info,
-                                   u16 seg, u8 start, u8 end,
-                                   phys_addr_t addr)
+static int setup_mcfg_map(struct acpi_pci_root_info *ci)
 {
        return 0;
 }
-static void teardown_mcfg_map(struct pci_root_info *info)
+
+static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
 {
 }
 #endif
 
-static void validate_resources(struct device *dev, struct list_head *crs_res,
-                              unsigned long type)
+static int pci_acpi_root_get_node(struct acpi_pci_root *root)
 {
-       LIST_HEAD(list);
-       struct resource *res1, *res2, *root = NULL;
-       struct resource_entry *tmp, *entry, *entry2;
-
-       BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
-       root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
-
-       list_splice_init(crs_res, &list);
-       resource_list_for_each_entry_safe(entry, tmp, &list) {
-               bool free = false;
-               resource_size_t end;
-
-               res1 = entry->res;
-               if (!(res1->flags & type))
-                       goto next;
-
-               /* Exclude non-addressable range or non-addressable portion */
-               end = min(res1->end, root->end);
-               if (end <= res1->start) {
-                       dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
-                                res1);
-                       free = true;
-                       goto next;
-               } else if (res1->end != end) {
-                       dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
-                                res1, (unsigned long long)end + 1,
-                                (unsigned long long)res1->end);
-                       res1->end = end;
-               }
-
-               resource_list_for_each_entry(entry2, crs_res) {
-                       res2 = entry2->res;
-                       if (!(res2->flags & type))
-                               continue;
-
-                       /*
-                        * I don't like throwing away windows because then
-                        * our resources no longer match the ACPI _CRS, but
-                        * the kernel resource tree doesn't allow overlaps.
-                        */
-                       if (resource_overlaps(res1, res2)) {
-                               res2->start = min(res1->start, res2->start);
-                               res2->end = max(res1->end, res2->end);
-                               dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
-                                        res2, res1);
-                               free = true;
-                               goto next;
-                       }
-               }
+       int busnum = root->secondary.start;
+       struct acpi_device *device = root->device;
+       int node = acpi_get_node(device->handle);
 
-next:
-               resource_list_del(entry);
-               if (free)
-                       resource_list_free_entry(entry);
-               else
-                       resource_list_add_tail(entry, crs_res);
+       if (node == NUMA_NO_NODE) {
+               node = x86_pci_root_bus_node(busnum);
+               if (node != 0 && node != NUMA_NO_NODE)
+                       dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
+                               node);
        }
+       if (node != NUMA_NO_NODE && !node_online(node))
+               node = NUMA_NO_NODE;
+
+       return node;
 }
 
-static void add_resources(struct pci_root_info *info,
-                         struct list_head *resources,
-                         struct list_head *crs_res)
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
 {
-       struct resource_entry *entry, *tmp;
-       struct resource *res, *conflict, *root = NULL;
-
-       validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM);
-       validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO);
-
-       resource_list_for_each_entry_safe(entry, tmp, crs_res) {
-               res = entry->res;
-               if (res->flags & IORESOURCE_MEM)
-                       root = &iomem_resource;
-               else if (res->flags & IORESOURCE_IO)
-                       root = &ioport_resource;
-               else
-                       BUG_ON(res);
-
-               conflict = insert_resource_conflict(root, res);
-               if (conflict) {
-                       dev_info(&info->bridge->dev,
-                                "ignoring host bridge window %pR (conflicts with %s %pR)\n",
-                                res, conflict->name, conflict);
-                       resource_list_destroy_entry(entry);
-               }
-       }
-
-       list_splice_tail(crs_res, resources);
+       return setup_mcfg_map(ci);
 }
 
-static void release_pci_root_info(struct pci_host_bridge *bridge)
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
 {
-       struct resource *res;
-       struct resource_entry *entry;
-       struct pci_root_info *info = bridge->release_data;
-
-       resource_list_for_each_entry(entry, &bridge->windows) {
-               res = entry->res;
-               if (res->parent &&
-                   (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
-                       release_resource(res);
-       }
-
-       teardown_mcfg_map(info);
-       kfree(info);
+       teardown_mcfg_map(ci);
+       kfree(container_of(ci, struct pci_root_info, common));
 }
 
 /*
@@ -358,50 +282,47 @@ static bool resource_is_pcicfg_ioport(struct resource *res)
                res->start == 0xCF8 && res->end == 0xCFF;
 }
 
-static void probe_pci_root_info(struct pci_root_info *info,
-                               struct acpi_device *device,
-                               int busnum, int domain,
-                               struct list_head *list)
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
 {
-       int ret;
+       struct acpi_device *device = ci->bridge;
+       int busnum = ci->root->secondary.start;
        struct resource_entry *entry, *tmp;
+       int status;
 
-       sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
-       info->bridge = device;
-       ret = acpi_dev_get_resources(device, list,
-                                    acpi_dev_filter_resource_type_cb,
-                                    (void *)(IORESOURCE_IO | IORESOURCE_MEM));
-       if (ret < 0)
-               dev_warn(&device->dev,
-                        "failed to parse _CRS method, error code %d\n", ret);
-       else if (ret == 0)
-               dev_dbg(&device->dev,
-                       "no IO and memory resources present in _CRS\n");
-       else
-               resource_list_for_each_entry_safe(entry, tmp, list) {
-                       if ((entry->res->flags & IORESOURCE_DISABLED) ||
-                           resource_is_pcicfg_ioport(entry->res))
+       status = acpi_pci_probe_root_resources(ci);
+       if (pci_use_crs) {
+               resource_list_for_each_entry_safe(entry, tmp, &ci->resources)
+                       if (resource_is_pcicfg_ioport(entry->res))
                                resource_list_destroy_entry(entry);
-                       else
-                               entry->res->name = info->name;
-               }
+               return status;
+       }
+
+       resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+               dev_printk(KERN_DEBUG, &device->dev,
+                          "host bridge window %pR (ignored)\n", entry->res);
+               resource_list_destroy_entry(entry);
+       }
+       x86_pci_root_bus_resources(busnum, &ci->resources);
+
+       return 0;
 }
 
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+       .pci_ops = &pci_root_ops,
+       .init_info = pci_acpi_root_init_info,
+       .release_info = pci_acpi_root_release_info,
+       .prepare_resources = pci_acpi_root_prepare_resources,
+};
+
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-       struct acpi_device *device = root->device;
-       struct pci_root_info *info;
        int domain = root->segment;
        int busnum = root->secondary.start;
-       struct resource_entry *res_entry;
-       LIST_HEAD(crs_res);
-       LIST_HEAD(resources);
+       int node = pci_acpi_root_get_node(root);
        struct pci_bus *bus;
-       struct pci_sysdata *sd;
-       int node;
 
        if (pci_ignore_seg)
-               domain = 0;
+               root->segment = domain = 0;
 
        if (domain && !pci_domains_supported) {
                printk(KERN_WARNING "pci_bus %04x:%02x: "
@@ -410,71 +331,33 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
                return NULL;
        }
 
-       node = acpi_get_node(device->handle);
-       if (node == NUMA_NO_NODE) {
-               node = x86_pci_root_bus_node(busnum);
-               if (node != 0 && node != NUMA_NO_NODE)
-                       dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
-                               node);
-       }
-
-       if (node != NUMA_NO_NODE && !node_online(node))
-               node = NUMA_NO_NODE;
-
-       info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
-       if (!info) {
-               printk(KERN_WARNING "pci_bus %04x:%02x: "
-                      "ignored (out of memory)\n", domain, busnum);
-               return NULL;
-       }
-
-       sd = &info->sd;
-       sd->domain = domain;
-       sd->node = node;
-       sd->companion = device;
-
        bus = pci_find_bus(domain, busnum);
        if (bus) {
                /*
                 * If the desired bus has been scanned already, replace
                 * its bus->sysdata.
                 */
-               memcpy(bus->sysdata, sd, sizeof(*sd));
-               kfree(info);
-       } else {
-               /* insert busn res at first */
-               pci_add_resource(&resources,  &root->secondary);
+               struct pci_sysdata sd = {
+                       .domain = domain,
+                       .node = node,
+                       .companion = root->device
+               };
 
-               /*
-                * _CRS with no apertures is normal, so only fall back to
-                * defaults or native bridge info if we're ignoring _CRS.
-                */
-               probe_pci_root_info(info, device, busnum, domain, &crs_res);
-               if (pci_use_crs) {
-                       add_resources(info, &resources, &crs_res);
-               } else {
-                       resource_list_for_each_entry(res_entry, &crs_res)
-                               dev_printk(KERN_DEBUG, &device->dev,
-                                          "host bridge window %pR (ignored)\n",
-                                          res_entry->res);
-                       resource_list_free(&crs_res);
-                       x86_pci_root_bus_resources(busnum, &resources);
-               }
-
-               if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
-                                   (u8)root->secondary.end, root->mcfg_addr))
-                       bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
-                                                 sd, &resources);
-
-               if (bus) {
-                       pci_scan_child_bus(bus);
-                       pci_set_host_bridge_release(
-                               to_pci_host_bridge(bus->bridge),
-                               release_pci_root_info, info);
-               } else {
-                       resource_list_free(&resources);
-                       teardown_mcfg_map(info);
-                       kfree(info);
+               memcpy(bus->sysdata, &sd, sizeof(sd));
+       } else {
+               struct pci_root_info *info;
+
+               info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
+               if (!info)
+                       dev_err(&root->device->dev,
+                               "pci_bus %04x:%02x: ignored (out of memory)\n",
+                               domain, busnum);
+               else {
+                       info->sd.domain = domain;
+                       info->sd.node = node;
+                       info->sd.companion = root->device;
+                       bus = acpi_pci_root_create(root, &acpi_pci_root_ops,
+                                                  &info->common, &info->sd);
                }
        }
 
@@ -487,9 +370,6 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
                        pcie_bus_configure_settings(child);
        }
 
-       if (bus && node != NUMA_NO_NODE)
-               dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
-
        return bus;
 }
 
index b97767dbc7c8e71d15d5d845f2388508ffc5b0ed..b9ad9feadc2d1a01da539d69fa735ebb61f607f2 100644 (file)
@@ -148,7 +148,7 @@ void __init time_init(void)
        local_timer_setup(0);
        setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
        sched_clock_register(ccount_sched_clock_read, 32, ccount_freq);
-       clocksource_of_init();
+       clocksource_probe();
 }
 
 /*
index 5d1015c26ff4cf9bb20adc92da1cb0f3921c3a14..25dbb76c02ccb0fd1d9b56d9956acb115d2e8419 100644 (file)
@@ -57,6 +57,15 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
        bool
 
+config ACPI_DEBUGGER
+       bool "In-kernel debugger (EXPERIMENTAL)"
+       select ACPI_DEBUG
+       help
+         Enable in-kernel debugging facilities: statistics, internal
+         object dump, single step control method execution.
+         This is still under development, currently enabling this only
+         results in the compilation of the ACPICA debugger files.
+
 config ACPI_SLEEP
        bool
        depends on SUSPEND || HIBERNATION
@@ -197,11 +206,25 @@ config ACPI_PROCESSOR_IDLE
        bool
        select CPU_IDLE
 
+config ACPI_CPPC_LIB
+       bool
+       depends on ACPI_PROCESSOR
+       depends on !ACPI_CPU_FREQ_PSS
+       select MAILBOX
+       select PCC
+       help
+         If this option is enabled, this file implements common functionality
+         to parse CPPC tables as described in the ACPI 5.1+ spec. The
+         routines implemented are meant to be used by other
+         drivers to control CPU performance using CPPC semantics.
+         If your platform does not support CPPC in firmware,
+         leave this option disabled.
+
 config ACPI_PROCESSOR
        tristate "Processor"
-       depends on X86 || IA64
-       select ACPI_PROCESSOR_IDLE
-       select ACPI_CPU_FREQ_PSS
+       depends on X86 || IA64 || ARM64
+       select ACPI_PROCESSOR_IDLE if X86 || IA64
+       select ACPI_CPU_FREQ_PSS if X86 || IA64
        default y
        help
          This driver adds support for the ACPI Processor package. It is required
index b5e7cd8a9c71ed22c8f7e21b3b41c0d8eecdfc9d..675eaf3371789618cdfb21ead69e121844dc006e 100644 (file)
@@ -78,6 +78,7 @@ obj-$(CONFIG_ACPI_HED)                += hed.o
 obj-$(CONFIG_ACPI_EC_DEBUGFS)  += ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)                += bgrt.o
+obj-$(CONFIG_ACPI_CPPC_LIB)    += cppc_acpi.o
 
 # processor has its own "processor." module_param namespace
 processor-y                    := processor_driver.o
index f51bd0d0bc17ceced34eab34463c8f048430de91..f9e0d09f7c66cf6bebfdaab992b3b1780b563766 100644 (file)
@@ -664,7 +664,7 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
-               .complete = acpi_subsys_complete,
+               .complete = pm_complete_with_resume_check,
                .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_lpss_suspend_late,
                .resume_early = acpi_lpss_resume_early,
index ae307ff36acb9ed76a7a4d360c7c1ad7f99353fa..8ea8211b2d589c6618d5037e40d653a3771edc55 100644 (file)
@@ -148,8 +148,6 @@ static int power_saving_thread(void *data)
        while (!kthread_should_stop()) {
                unsigned long expire_time;
 
-               try_to_freeze();
-
                /* round robin to cpus */
                expire_time = last_jiffies + round_robin_time * HZ;
                if (time_before(expire_time, jiffies)) {
index c58940b231d69df0c135bd5f821dbef64ef5755c..48fc3ad13a4bbcfe5fc12a5db772855b5add0780 100644 (file)
@@ -316,7 +316,7 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
        {""},
 };
 
-static bool matching_id(char *idstr, char *list_id)
+static bool matching_id(const char *idstr, const char *list_id)
 {
        int i;
 
@@ -333,7 +333,7 @@ static bool matching_id(char *idstr, char *list_id)
        return true;
 }
 
-static bool acpi_pnp_match(char *idstr, const struct acpi_device_id **matchid)
+static bool acpi_pnp_match(const char *idstr, const struct acpi_device_id **matchid)
 {
        const struct acpi_device_id *devid;
 
index 985b8a83184e1e366ad39c3b326a1619b0b97bcb..6979186dbd4b45bd19b60b51d4fd76c76abd683f 100644 (file)
@@ -164,6 +164,24 @@ static int acpi_processor_errata(void)
    -------------------------------------------------------------------------- */
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
+int __weak acpi_map_cpu(acpi_handle handle,
+               phys_cpuid_t physid, int *pcpu)
+{
+       return -ENODEV;
+}
+
+int __weak acpi_unmap_cpu(int cpu)
+{
+       return -ENODEV;
+}
+
+int __weak arch_register_cpu(int cpu)
+{
+       return -ENODEV;
+}
+
+void __weak arch_unregister_cpu(int cpu) {}
+
 static int acpi_processor_hotadd_init(struct acpi_processor *pr)
 {
        unsigned long long sta;
index fedcc16b56cc5771ce2e6bddadb0705c84122b81..885936f7954287dcc15ef3048a1546137b25c61e 100644 (file)
@@ -123,7 +123,6 @@ acpi-y +=           \
        rsaddr.o        \
        rscalc.o        \
        rscreate.o      \
-       rsdump.o        \
        rsdumpinfo.o    \
        rsinfo.o        \
        rsio.o          \
@@ -178,7 +177,24 @@ acpi-y +=          \
        utxferror.o     \
        utxfmutex.o
 
+acpi-$(CONFIG_ACPI_DEBUGGER) +=        \
+       dbcmds.o                \
+       dbconvert.o             \
+       dbdisply.o              \
+       dbexec.o                \
+       dbhistry.o              \
+       dbinput.o               \
+       dbmethod.o              \
+       dbnames.o               \
+       dbobject.o              \
+       dbstats.o               \
+       dbutils.o               \
+       dbxface.o               \
+       rsdump.o                \
+
 acpi-$(ACPI_FUTURE_USAGE) +=   \
+       dbfileio.o              \
+       dbtest.o                \
        utcache.o               \
        utfileio.o              \
        utprint.o               \
index e9f0833e818d17c641a75adaa01c1f6fd4dcd4f3..e4cc48fbf4eef49bdcbac4a879e0739a0faac25f 100644 (file)
@@ -88,7 +88,7 @@
        acpi_os_printf (" %-18s%s\n", name, description);
 
 #define FILE_SUFFIX_DISASSEMBLY     "dsl"
-#define ACPI_TABLE_FILE_SUFFIX      ".dat"
+#define FILE_SUFFIX_BINARY_TABLE    ".dat"     /* Needs the dot */
 
 /*
  * getopt
index eb2e926d8218f04c6bedab32f8dfc5d5febfce90..c928ba494c4000ff71a54bcd4ea022082ee7ccc6 100644 (file)
 #ifndef __ACDEBUG_H__
 #define __ACDEBUG_H__
 
+/* The debugger is used in conjunction with the disassembler most of time */
+
+#ifdef ACPI_DISASSEMBLER
+#include "acdisasm.h"
+#endif
+
 #define ACPI_DEBUG_BUFFER_SIZE  0x4000 /* 16K buffer for return objects */
 
 struct acpi_db_command_info {
index 4dde37c3d8fcba549ad1eb978bf23466321e9152..faa97604d878e01a41707494435ed16d7f9b81fc 100644 (file)
@@ -325,9 +325,9 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
 
 #ifdef ACPI_DEBUGGER
 
-ACPI_INIT_GLOBAL(u8, acpi_gbl_db_terminate_threads, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
+ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID);
 
 ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods);
 ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
@@ -337,6 +337,8 @@ ACPI_GLOBAL(char *, acpi_gbl_db_filename);
 ACPI_GLOBAL(u32, acpi_gbl_db_debug_level);
 ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level);
 ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node);
+ACPI_GLOBAL(u8, acpi_gbl_db_terminate_loop);
+ACPI_GLOBAL(u8, acpi_gbl_db_threads_terminated);
 
 ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]);
 ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
@@ -358,6 +360,9 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
 ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
 ACPI_GLOBAL(u32, acpi_gbl_num_objects);
 
+ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_ready);
+ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_complete);
+
 #endif                         /* ACPI_DEBUGGER */
 
 /*****************************************************************************
index e820ed8f173f01b19322b426b66df6620aec8ce0..e9e936e78154c5eeed8134d1c04d317fd535a3f6 100644 (file)
@@ -397,12 +397,10 @@ void
 acpi_ex_dump_operands(union acpi_operand_object **operands,
                      const char *opcode_name, u32 num_opcodes);
 
-#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ex_dump_object_descriptor(union acpi_operand_object *object, u32 flags);
 
 void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 /*
  * exnames - AML namestring support
index 6f708267ad8cbf0d172704772a8b62d85783c3b1..e1dd784d851599e12a8adbf831d3f560f3c0dc94 100644 (file)
@@ -83,10 +83,8 @@ union acpi_parse_object;
 #define ACPI_MTX_EVENTS                 3      /* Data for ACPI events */
 #define ACPI_MTX_CACHES                 4      /* Internal caches, general purposes */
 #define ACPI_MTX_MEMORY                 5      /* Debug memory tracking lists */
-#define ACPI_MTX_DEBUG_CMD_COMPLETE     6      /* AML debugger */
-#define ACPI_MTX_DEBUG_CMD_READY        7      /* AML debugger */
 
-#define ACPI_MAX_MUTEX                  7
+#define ACPI_MAX_MUTEX                  5
 #define ACPI_NUM_MUTEX                  ACPI_MAX_MUTEX+1
 
 /* Lock structure for reader/writer interfaces */
@@ -111,6 +109,14 @@ struct acpi_rw_lock {
 
 #define ACPI_MUTEX_NOT_ACQUIRED         (acpi_thread_id) 0
 
+/* This Thread ID means an invalid thread ID */
+
+#ifdef ACPI_OS_INVALID_THREAD_ID
+#define ACPI_INVALID_THREAD_ID          ACPI_OS_INVALID_THREAD_ID
+#else
+#define ACPI_INVALID_THREAD_ID          ((acpi_thread_id) 0xFFFFFFFF)
+#endif
+
 /* Table for the global mutexes */
 
 struct acpi_mutex_info {
@@ -287,13 +293,17 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
 #define ACPI_BTYPE_BUFFER_FIELD         0x00002000
 #define ACPI_BTYPE_DDB_HANDLE           0x00004000
 #define ACPI_BTYPE_DEBUG_OBJECT         0x00008000
-#define ACPI_BTYPE_REFERENCE            0x00010000
+#define ACPI_BTYPE_REFERENCE_OBJECT     0x00010000     /* From Index(), ref_of(), etc (type6_opcodes) */
 #define ACPI_BTYPE_RESOURCE             0x00020000
+#define ACPI_BTYPE_NAMED_REFERENCE      0x00040000     /* Generic unresolved Name or Namepath */
 
 #define ACPI_BTYPE_COMPUTE_DATA         (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER)
 
 #define ACPI_BTYPE_DATA                 (ACPI_BTYPE_COMPUTE_DATA  | ACPI_BTYPE_PACKAGE)
-#define ACPI_BTYPE_DATA_REFERENCE       (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE)
+
+       /* Used by Copy, de_ref_of, Store, Printf, Fprintf */
+
+#define ACPI_BTYPE_DATA_REFERENCE       (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE_OBJECT | ACPI_BTYPE_DDB_HANDLE)
 #define ACPI_BTYPE_DEVICE_OBJECTS       (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR)
 #define ACPI_BTYPE_OBJECTS_AND_REFS     0x0001FFFF     /* ARG or LOCAL */
 #define ACPI_BTYPE_ALL_OBJECTS          0x0000FFFF
@@ -848,7 +858,7 @@ struct acpi_parse_state {
 #define ACPI_PARSEOP_PARAMLIST          0x02
 #define ACPI_PARSEOP_EMPTY_TERMLIST     0x04
 #define ACPI_PARSEOP_PREDEF_CHECKED     0x08
-#define ACPI_PARSEOP_SPECIAL            0x10
+#define ACPI_PARSEOP_CLOSING_PAREN      0x10
 #define ACPI_PARSEOP_COMPOUND           0x20
 #define ACPI_PARSEOP_ASSIGNMENT         0x40
 
index ea0d9076d4087a697499b728ed766c9ddb484837..5d261c942a0d129150ab76c05e82af9b1ab43a2e 100644 (file)
@@ -193,9 +193,7 @@ acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
 /*
  * nsdump - Namespace dump/print utilities
  */
-#ifdef ACPI_FUTURE_USAGE
 void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level);
 
@@ -208,7 +206,6 @@ acpi_status
 acpi_ns_dump_one_object(acpi_handle obj_handle,
                        u32 level, void *context, void **return_value);
 
-#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ns_dump_objects(acpi_object_type type,
                     u8 display_type,
@@ -220,7 +217,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
                          u8 display_type,
                          u32 max_depth,
                          acpi_owner_id owner_id, acpi_handle start_handle);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 /*
  * nseval - Namespace evaluation functions
index fd85ad05a24ac716ec33214e8ec79fdc7d6f9014..f9acf92fa0bc2121b6a50a99874979d63e0fe37b 100644 (file)
 #define ARGI_ARG4                       ARG_NONE
 #define ARGI_ARG5                       ARG_NONE
 #define ARGI_ARG6                       ARG_NONE
-#define ARGI_BANK_FIELD_OP              ARGI_INVALID_OPCODE
+#define ARGI_BANK_FIELD_OP              ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_BIT_AND_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BIT_NAND_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BIT_NOR_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_SLEEP_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STALL_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STATICSTRING_OP            ARGI_INVALID_OPCODE
-#define ARGI_STORE_OP                   ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
+#define ARGI_STORE_OP                   ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_STORE_TARGET)
 #define ARGI_STRING_OP                  ARGI_INVALID_OPCODE
 #define ARGI_SUBTRACT_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_THERMAL_ZONE_OP            ARGI_INVALID_OPCODE
index 6021ccfb0b1c8cad1e80bd350355a2698f085320..8fc8c7cea87963ceb40c8a3184290ebe23b0d331 100644 (file)
@@ -194,10 +194,8 @@ union acpi_parse_object *acpi_ps_find(union acpi_parse_object *scope,
 
 union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn);
 
-#ifdef ACPI_FUTURE_USAGE
 union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
                                                union acpi_parse_object *op);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 /*
  * pswalk - parse tree walk routines
@@ -235,9 +233,7 @@ void acpi_ps_free_op(union acpi_parse_object *op);
 
 u8 acpi_ps_is_leading_char(u32 c);
 
-#ifdef ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object *op);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 void acpi_ps_set_name(union acpi_parse_object *op, u32 name);
 
index fb2aa5066f3fa8c980cc9184a6965bda3091fac8..8b8fef6cc32df7dac1d77191172550b5bf7b3d2c 100644 (file)
@@ -635,9 +635,7 @@ void
 acpi_ut_free_and_track(void *address,
                       u32 component, const char *module, u32 line);
 
-#ifdef ACPI_FUTURE_USAGE
 void acpi_ut_dump_allocation_info(void);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 void acpi_ut_dump_allocations(u32 component, const char *module);
 
index be9fd009cb28fa8e9d74c1826f3641cc2ebddabb..883f20cfa69809674d04db7070118bda7d2400d5 100644 (file)
 #define ARGI_TARGETREF              0x0F       /* Target, subject to implicit conversion */
 #define ARGI_FIXED_TARGET           0x10       /* Target, no implicit conversion */
 #define ARGI_SIMPLE_TARGET          0x11       /* Name, Local, Arg -- no implicit conversion */
+#define ARGI_STORE_TARGET           0x12       /* Target for store is TARGETREF + package objects */
 
 /* Multiple/complex types */
 
-#define ARGI_DATAOBJECT             0x12       /* Buffer, String, package or reference to a node - Used only by size_of operator */
-#define ARGI_COMPLEXOBJ             0x13       /* Buffer, String, or package (Used by INDEX op only) */
-#define ARGI_REF_OR_STRING          0x14       /* Reference or String (Used by DEREFOF op only) */
-#define ARGI_REGION_OR_BUFFER       0x15       /* Used by LOAD op only */
-#define ARGI_DATAREFOBJ             0x16
+#define ARGI_DATAOBJECT             0x13       /* Buffer, String, package or reference to a node - Used only by size_of operator */
+#define ARGI_COMPLEXOBJ             0x14       /* Buffer, String, or package (Used by INDEX op only) */
+#define ARGI_REF_OR_STRING          0x15       /* Reference or String (Used by DEREFOF op only) */
+#define ARGI_REGION_OR_BUFFER       0x16       /* Used by LOAD op only */
+#define ARGI_DATAREFOBJ             0x17
 
 /* Note: types above can expand to 0x1F maximum */
 
diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c
new file mode 100644 (file)
index 0000000..30414b3
--- /dev/null
@@ -0,0 +1,1187 @@
+/*******************************************************************************
+ *
+ * Module Name: dbcmds - Miscellaneous debug commands and output routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+#include "acresrc.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbcmds")
+
+/* Local prototypes */
+static void
+acpi_dm_compare_aml_resources(u8 *aml1_buffer,
+                             acpi_rsdesc_size aml1_buffer_length,
+                             u8 *aml2_buffer,
+                             acpi_rsdesc_size aml2_buffer_length);
+
+static acpi_status
+acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name);
+
+static acpi_status
+acpi_db_resource_callback(struct acpi_resource *resource, void *context);
+
+static acpi_status
+acpi_db_device_resources(acpi_handle obj_handle,
+                        u32 nesting_level, void *context, void **return_value);
+
+static void acpi_db_do_one_sleep_state(u8 sleep_state);
+
+static char *acpi_db_trace_method_name = NULL;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_node
+ *
+ * PARAMETERS:  in_string           - String to convert
+ *
+ * RETURN:      Pointer to a NS node
+ *
+ * DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or
+ *              alphanumeric strings.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string)
+{
+       struct acpi_namespace_node *node;
+       acpi_size address;
+
+       if ((*in_string >= 0x30) && (*in_string <= 0x39)) {
+
+               /* Numeric argument, convert */
+
+               address = strtoul(in_string, NULL, 16);
+               node = ACPI_TO_POINTER(address);
+               if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
+                       acpi_os_printf("Address %p is invalid", node);
+                       return (NULL);
+               }
+
+               /* Make sure pointer is valid NS node */
+
+               if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+                       acpi_os_printf
+                           ("Address %p is not a valid namespace node [%s]\n",
+                            node, acpi_ut_get_descriptor_name(node));
+                       return (NULL);
+               }
+       } else {
+               /*
+                * Alpha argument: The parameter is a name string that must be
+                * resolved to a Namespace object.
+                */
+               node = acpi_db_local_ns_lookup(in_string);
+               if (!node) {
+                       acpi_os_printf
+                           ("Could not find [%s] in namespace, defaulting to root node\n",
+                            in_string);
+                       node = acpi_gbl_root_node;
+               }
+       }
+
+       return (node);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_sleep
+ *
+ * PARAMETERS:  object_arg          - Desired sleep state (0-5). NULL means
+ *                                    invoke all possible sleep states.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Simulate sleep/wake sequences
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_sleep(char *object_arg)
+{
+       u8 sleep_state;
+       u32 i;
+
+       ACPI_FUNCTION_TRACE(acpi_db_sleep);
+
+       /* Null input (no arguments) means to invoke all sleep states */
+
+       if (!object_arg) {
+               acpi_os_printf("Invoking all possible sleep states, 0-%d\n",
+                              ACPI_S_STATES_MAX);
+
+               for (i = 0; i <= ACPI_S_STATES_MAX; i++) {
+                       acpi_db_do_one_sleep_state((u8)i);
+               }
+
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Convert argument to binary and invoke the sleep state */
+
+       sleep_state = (u8)strtoul(object_arg, NULL, 0);
+       acpi_db_do_one_sleep_state(sleep_state);
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_do_one_sleep_state
+ *
+ * PARAMETERS:  sleep_state         - Desired sleep state (0-5)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate a sleep/wake sequence
+ *
+ ******************************************************************************/
+
+static void acpi_db_do_one_sleep_state(u8 sleep_state)
+{
+       acpi_status status;
+       u8 sleep_type_a;
+       u8 sleep_type_b;
+
+       /* Validate parameter */
+
+       if (sleep_state > ACPI_S_STATES_MAX) {
+               acpi_os_printf("Sleep state %d out of range (%d max)\n",
+                              sleep_state, ACPI_S_STATES_MAX);
+               return;
+       }
+
+       acpi_os_printf("\n---- Invoking sleep state S%d (%s):\n",
+                      sleep_state, acpi_gbl_sleep_state_names[sleep_state]);
+
+       /* Get the values for the sleep type registers (for display only) */
+
+       status =
+           acpi_get_sleep_type_data(sleep_state, &sleep_type_a, &sleep_type_b);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not evaluate [%s] method, %s\n",
+                              acpi_gbl_sleep_state_names[sleep_state],
+                              acpi_format_exception(status));
+               return;
+       }
+
+       acpi_os_printf
+           ("Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n",
+            sleep_state, sleep_type_a, sleep_type_b);
+
+       /* Invoke the various sleep/wake interfaces */
+
+       acpi_os_printf("**** Sleep: Prepare to sleep (S%d) ****\n",
+                      sleep_state);
+       status = acpi_enter_sleep_state_prep(sleep_state);
+       if (ACPI_FAILURE(status)) {
+               goto error_exit;
+       }
+
+       acpi_os_printf("**** Sleep: Going to sleep (S%d) ****\n", sleep_state);
+       status = acpi_enter_sleep_state(sleep_state);
+       if (ACPI_FAILURE(status)) {
+               goto error_exit;
+       }
+
+       acpi_os_printf("**** Wake: Prepare to return from sleep (S%d) ****\n",
+                      sleep_state);
+       status = acpi_leave_sleep_state_prep(sleep_state);
+       if (ACPI_FAILURE(status)) {
+               goto error_exit;
+       }
+
+       acpi_os_printf("**** Wake: Return from sleep (S%d) ****\n",
+                      sleep_state);
+       status = acpi_leave_sleep_state(sleep_state);
+       if (ACPI_FAILURE(status)) {
+               goto error_exit;
+       }
+
+       return;
+
+error_exit:
+       ACPI_EXCEPTION((AE_INFO, status, "During invocation of sleep state S%d",
+                       sleep_state));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_locks
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about internal mutexes.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_locks(void)
+{
+       u32 i;
+
+       for (i = 0; i < ACPI_MAX_MUTEX; i++) {
+               acpi_os_printf("%26s : %s\n", acpi_ut_get_mutex_name(i),
+                              acpi_gbl_mutex_info[i].thread_id ==
+                              ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked");
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_table_info
+ *
+ * PARAMETERS:  table_arg           - Name of table to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about loaded tables. Current
+ *              implementation displays all loaded tables.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_table_info(char *table_arg)
+{
+       u32 i;
+       struct acpi_table_desc *table_desc;
+       acpi_status status;
+
+       /* Header */
+
+       acpi_os_printf("Idx ID  Status Type                    "
+                      "TableHeader (Sig, Address, Length, Misc)\n");
+
+       /* Walk the entire root table list */
+
+       for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+               table_desc = &acpi_gbl_root_table_list.tables[i];
+
+               /* Index and Table ID */
+
+               acpi_os_printf("%3u %.2u ", i, table_desc->owner_id);
+
+               /* Decode the table flags */
+
+               if (!(table_desc->flags & ACPI_TABLE_IS_LOADED)) {
+                       acpi_os_printf("NotLoaded ");
+               } else {
+                       acpi_os_printf(" Loaded ");
+               }
+
+               switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+               case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+                       acpi_os_printf("External/virtual ");
+                       break;
+
+               case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+                       acpi_os_printf("Internal/physical ");
+                       break;
+
+               case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+
+                       acpi_os_printf("Internal/virtual ");
+                       break;
+
+               default:
+
+                       acpi_os_printf("INVALID TYPE    ");
+                       break;
+               }
+
+               /* Make sure that the table is mapped */
+
+               status = acpi_tb_validate_table(table_desc);
+               if (ACPI_FAILURE(status)) {
+                       return;
+               }
+
+               /* Dump the table header */
+
+               if (table_desc->pointer) {
+                       acpi_tb_print_table_header(table_desc->address,
+                                                  table_desc->pointer);
+               } else {
+                       /* If the pointer is null, the table has been unloaded */
+
+                       ACPI_INFO((AE_INFO, "%4.4s - Table has been unloaded",
+                                  table_desc->signature.ascii));
+               }
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_unload_acpi_table
+ *
+ * PARAMETERS:  object_name         - Namespace pathname for an object that
+ *                                    is owned by the table to be unloaded
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Unload an ACPI table, via any namespace node that is owned
+ *              by the table.
+ *
+ ******************************************************************************/
+
+void acpi_db_unload_acpi_table(char *object_name)
+{
+       struct acpi_namespace_node *node;
+       acpi_status status;
+
+       /* Translate name to an Named object */
+
+       node = acpi_db_convert_to_node(object_name);
+       if (!node) {
+               return;
+       }
+
+       status = acpi_unload_parent_table(ACPI_CAST_PTR(acpi_handle, node));
+       if (ACPI_SUCCESS(status)) {
+               acpi_os_printf("Parent of [%s] (%p) unloaded and uninstalled\n",
+                              object_name, node);
+       } else {
+               acpi_os_printf("%s, while unloading parent table of [%s]\n",
+                              acpi_format_exception(status), object_name);
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_send_notify
+ *
+ * PARAMETERS:  name                - Name of ACPI object where to send notify
+ *              value               - Value of the notify to send.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Send an ACPI notification. The value specified is sent to the
+ *              named object as an ACPI notify.
+ *
+ ******************************************************************************/
+
+void acpi_db_send_notify(char *name, u32 value)
+{
+       struct acpi_namespace_node *node;
+       acpi_status status;
+
+       /* Translate name to an Named object */
+
+       node = acpi_db_convert_to_node(name);
+       if (!node) {
+               return;
+       }
+
+       /* Dispatch the notify if legal */
+
+       if (acpi_ev_is_notify_object(node)) {
+               status = acpi_ev_queue_notify_request(node, value);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not queue notify\n");
+               }
+       } else {
+               acpi_os_printf("Named object [%4.4s] Type %s, "
+                              "must be Device/Thermal/Processor type\n",
+                              acpi_ut_get_node_name(node),
+                              acpi_ut_get_type_name(node->type));
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_interfaces
+ *
+ * PARAMETERS:  action_arg          - Null, "install", or "remove"
+ *              interface_name_arg  - Name for install/remove options
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display or modify the global _OSI interface list
+ *
+ ******************************************************************************/
+
+void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg)
+{
+       struct acpi_interface_info *next_interface;
+       char *sub_string;
+       acpi_status status;
+
+       /* If no arguments, just display current interface list */
+
+       if (!action_arg) {
+               (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex,
+                                           ACPI_WAIT_FOREVER);
+
+               next_interface = acpi_gbl_supported_interfaces;
+               while (next_interface) {
+                       if (!(next_interface->flags & ACPI_OSI_INVALID)) {
+                               acpi_os_printf("%s\n", next_interface->name);
+                       }
+
+                       next_interface = next_interface->next;
+               }
+
+               acpi_os_release_mutex(acpi_gbl_osi_mutex);
+               return;
+       }
+
+       /* If action_arg exists, so must interface_name_arg */
+
+       if (!interface_name_arg) {
+               acpi_os_printf("Missing Interface Name argument\n");
+               return;
+       }
+
+       /* Uppercase the action for match below */
+
+       acpi_ut_strupr(action_arg);
+
+       /* install - install an interface */
+
+       sub_string = strstr("INSTALL", action_arg);
+       if (sub_string) {
+               status = acpi_install_interface(interface_name_arg);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("%s, while installing \"%s\"\n",
+                                      acpi_format_exception(status),
+                                      interface_name_arg);
+               }
+               return;
+       }
+
+       /* remove - remove an interface */
+
+       sub_string = strstr("REMOVE", action_arg);
+       if (sub_string) {
+               status = acpi_remove_interface(interface_name_arg);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("%s, while removing \"%s\"\n",
+                                      acpi_format_exception(status),
+                                      interface_name_arg);
+               }
+               return;
+       }
+
+       /* Invalid action_arg */
+
+       acpi_os_printf("Invalid action argument: %s\n", action_arg);
+       return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_template
+ *
+ * PARAMETERS:  buffer_arg          - Buffer name or address
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump a buffer that contains a resource template
+ *
+ ******************************************************************************/
+
+void acpi_db_display_template(char *buffer_arg)
+{
+       struct acpi_namespace_node *node;
+       acpi_status status;
+       struct acpi_buffer return_buffer;
+
+       /* Translate buffer_arg to an Named object */
+
+       node = acpi_db_convert_to_node(buffer_arg);
+       if (!node || (node == acpi_gbl_root_node)) {
+               acpi_os_printf("Invalid argument: %s\n", buffer_arg);
+               return;
+       }
+
+       /* We must have a buffer object */
+
+       if (node->type != ACPI_TYPE_BUFFER) {
+               acpi_os_printf
+                   ("Not a Buffer object, cannot be a template: %s\n",
+                    buffer_arg);
+               return;
+       }
+
+       return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+       return_buffer.pointer = acpi_gbl_db_buffer;
+
+       /* Attempt to convert the raw buffer to a resource list */
+
+       status = acpi_rs_create_resource_list(node->object, &return_buffer);
+
+       acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+       acpi_dbg_level |= ACPI_LV_RESOURCES;
+
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf
+                   ("Could not convert Buffer to a resource list: %s, %s\n",
+                    buffer_arg, acpi_format_exception(status));
+               goto dump_buffer;
+       }
+
+       /* Now we can dump the resource list */
+
+       acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
+                                                return_buffer.pointer));
+
+dump_buffer:
+       acpi_os_printf("\nRaw data buffer:\n");
+       acpi_ut_debug_dump_buffer((u8 *)node->object->buffer.pointer,
+                                 node->object->buffer.length,
+                                 DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
+
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+       return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_dm_compare_aml_resources
+ *
+ * PARAMETERS:  aml1_buffer         - Contains first resource list
+ *              aml1_buffer_length  - Length of first resource list
+ *              aml2_buffer         - Contains second resource list
+ *              aml2_buffer_length  - Length of second resource list
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in
+ *              order to isolate a miscompare to an individual resource)
+ *
+ ******************************************************************************/
+
+static void
+acpi_dm_compare_aml_resources(u8 *aml1_buffer,
+                             acpi_rsdesc_size aml1_buffer_length,
+                             u8 *aml2_buffer,
+                             acpi_rsdesc_size aml2_buffer_length)
+{
+       u8 *aml1;
+       u8 *aml2;
+       u8 *aml1_end;
+       u8 *aml2_end;
+       acpi_rsdesc_size aml1_length;
+       acpi_rsdesc_size aml2_length;
+       acpi_rsdesc_size offset = 0;
+       u8 resource_type;
+       u32 count = 0;
+       u32 i;
+
+       /* Compare overall buffer sizes (may be different due to size rounding) */
+
+       if (aml1_buffer_length != aml2_buffer_length) {
+               acpi_os_printf("**** Buffer length mismatch in converted "
+                              "AML: Original %X, New %X ****\n",
+                              aml1_buffer_length, aml2_buffer_length);
+       }
+
+       aml1 = aml1_buffer;
+       aml2 = aml2_buffer;
+       aml1_end = aml1_buffer + aml1_buffer_length;
+       aml2_end = aml2_buffer + aml2_buffer_length;
+
+       /* Walk the descriptor lists, comparing each descriptor */
+
+       while ((aml1 < aml1_end) && (aml2 < aml2_end)) {
+
+               /* Get the lengths of each descriptor */
+
+               aml1_length = acpi_ut_get_descriptor_length(aml1);
+               aml2_length = acpi_ut_get_descriptor_length(aml2);
+               resource_type = acpi_ut_get_resource_type(aml1);
+
+               /* Check for descriptor length match */
+
+               if (aml1_length != aml2_length) {
+                       acpi_os_printf
+                           ("**** Length mismatch in descriptor [%.2X] type %2.2X, "
+                            "Offset %8.8X Len1 %X, Len2 %X ****\n", count,
+                            resource_type, offset, aml1_length, aml2_length);
+               }
+
+               /* Check for descriptor byte match */
+
+               else if (memcmp(aml1, aml2, aml1_length)) {
+                       acpi_os_printf
+                           ("**** Data mismatch in descriptor [%.2X] type %2.2X, "
+                            "Offset %8.8X ****\n", count, resource_type,
+                            offset);
+
+                       for (i = 0; i < aml1_length; i++) {
+                               if (aml1[i] != aml2[i]) {
+                                       acpi_os_printf
+                                           ("Mismatch at byte offset %.2X: is %2.2X, "
+                                            "should be %2.2X\n", i, aml2[i],
+                                            aml1[i]);
+                               }
+                       }
+               }
+
+               /* Exit on end_tag descriptor */
+
+               if (resource_type == ACPI_RESOURCE_NAME_END_TAG) {
+                       return;
+               }
+
+               /* Point to next descriptor in each buffer */
+
+               count++;
+               offset += aml1_length;
+               aml1 += aml1_length;
+               aml2 += aml2_length;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_dm_test_resource_conversion
+ *
+ * PARAMETERS:  node                - Parent device node
+ *              name                - resource method name (_CRS)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Compare the original AML with a conversion of the AML to
+ *              internal resource list, then back to AML.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name)
+{
+       acpi_status status;
+       struct acpi_buffer return_buffer;
+       struct acpi_buffer resource_buffer;
+       struct acpi_buffer new_aml;
+       union acpi_object *original_aml;
+
+       acpi_os_printf("Resource Conversion Comparison:\n");
+
+       new_aml.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       resource_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+       /* Get the original _CRS AML resource template */
+
+       status = acpi_evaluate_object(node, name, NULL, &return_buffer);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not obtain %s: %s\n",
+                              name, acpi_format_exception(status));
+               return (status);
+       }
+
+       /* Get the AML resource template, converted to internal resource structs */
+
+       status = acpi_get_current_resources(node, &resource_buffer);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
+                              acpi_format_exception(status));
+               goto exit1;
+       }
+
+       /* Convert internal resource list to external AML resource template */
+
+       status = acpi_rs_create_aml_resources(&resource_buffer, &new_aml);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("AcpiRsCreateAmlResources failed: %s\n",
+                              acpi_format_exception(status));
+               goto exit2;
+       }
+
+       /* Compare original AML to the newly created AML resource list */
+
+       original_aml = return_buffer.pointer;
+
+       acpi_dm_compare_aml_resources(original_aml->buffer.pointer,
+                                     (acpi_rsdesc_size) original_aml->buffer.
+                                     length, new_aml.pointer,
+                                     (acpi_rsdesc_size) new_aml.length);
+
+       /* Cleanup and exit */
+
+       ACPI_FREE(new_aml.pointer);
+exit2:
+       ACPI_FREE(resource_buffer.pointer);
+exit1:
+       ACPI_FREE(return_buffer.pointer);
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_resource_callback
+ *
+ * PARAMETERS:  acpi_walk_resource_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Simple callback to exercise acpi_walk_resources and
+ *              acpi_walk_resource_buffer.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_resource_callback(struct acpi_resource *resource, void *context)
+{
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_device_resources
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_device_resources(acpi_handle obj_handle,
+                        u32 nesting_level, void *context, void **return_value)
+{
+       struct acpi_namespace_node *node;
+       struct acpi_namespace_node *prt_node = NULL;
+       struct acpi_namespace_node *crs_node = NULL;
+       struct acpi_namespace_node *prs_node = NULL;
+       struct acpi_namespace_node *aei_node = NULL;
+       char *parent_path;
+       struct acpi_buffer return_buffer;
+       acpi_status status;
+
+       node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+       parent_path = acpi_ns_get_external_pathname(node);
+       if (!parent_path) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Get handles to the resource methods for this device */
+
+       (void)acpi_get_handle(node, METHOD_NAME__PRT,
+                             ACPI_CAST_PTR(acpi_handle, &prt_node));
+       (void)acpi_get_handle(node, METHOD_NAME__CRS,
+                             ACPI_CAST_PTR(acpi_handle, &crs_node));
+       (void)acpi_get_handle(node, METHOD_NAME__PRS,
+                             ACPI_CAST_PTR(acpi_handle, &prs_node));
+       (void)acpi_get_handle(node, METHOD_NAME__AEI,
+                             ACPI_CAST_PTR(acpi_handle, &aei_node));
+
+       if (!prt_node && !crs_node && !prs_node && !aei_node) {
+               goto cleanup;   /* Nothing to do */
+       }
+
+       acpi_os_printf("\nDevice: %s\n", parent_path);
+
+       /* Prepare for a return object of arbitrary size */
+
+       return_buffer.pointer = acpi_gbl_db_buffer;
+       return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+       /* _PRT */
+
+       if (prt_node) {
+               acpi_os_printf("Evaluating _PRT\n");
+
+               status =
+                   acpi_evaluate_object(prt_node, NULL, NULL, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not evaluate _PRT: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_crs;
+               }
+
+               return_buffer.pointer = acpi_gbl_db_buffer;
+               return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+               status = acpi_get_irq_routing_table(node, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("GetIrqRoutingTable failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_crs;
+               }
+
+               acpi_rs_dump_irq_list(ACPI_CAST_PTR(u8, acpi_gbl_db_buffer));
+       }
+
+       /* _CRS */
+
+get_crs:
+       if (crs_node) {
+               acpi_os_printf("Evaluating _CRS\n");
+
+               return_buffer.pointer = acpi_gbl_db_buffer;
+               return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+               status =
+                   acpi_evaluate_object(crs_node, NULL, NULL, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not evaluate _CRS: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_prs;
+               }
+
+               /* This code exercises the acpi_walk_resources interface */
+
+               status = acpi_walk_resources(node, METHOD_NAME__CRS,
+                                            acpi_db_resource_callback, NULL);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiWalkResources failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_prs;
+               }
+
+               /* Get the _CRS resource list (test ALLOCATE buffer) */
+
+               return_buffer.pointer = NULL;
+               return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+               status = acpi_get_current_resources(node, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_prs;
+               }
+
+               /* This code exercises the acpi_walk_resource_buffer interface */
+
+               status = acpi_walk_resource_buffer(&return_buffer,
+                                                  acpi_db_resource_callback,
+                                                  NULL);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiWalkResourceBuffer failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto end_crs;
+               }
+
+               /* Dump the _CRS resource list */
+
+               acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
+                                                        return_buffer.
+                                                        pointer));
+
+               /*
+                * Perform comparison of original AML to newly created AML. This
+                * tests both the AML->Resource conversion and the Resource->AML
+                * conversion.
+                */
+               (void)acpi_dm_test_resource_conversion(node, METHOD_NAME__CRS);
+
+               /* Execute _SRS with the resource list */
+
+               acpi_os_printf("Evaluating _SRS\n");
+
+               status = acpi_set_current_resources(node, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiSetCurrentResources failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto end_crs;
+               }
+
+end_crs:
+               ACPI_FREE(return_buffer.pointer);
+       }
+
+       /* _PRS */
+
+get_prs:
+       if (prs_node) {
+               acpi_os_printf("Evaluating _PRS\n");
+
+               return_buffer.pointer = acpi_gbl_db_buffer;
+               return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+               status =
+                   acpi_evaluate_object(prs_node, NULL, NULL, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not evaluate _PRS: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_aei;
+               }
+
+               return_buffer.pointer = acpi_gbl_db_buffer;
+               return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+               status = acpi_get_possible_resources(node, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiGetPossibleResources failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto get_aei;
+               }
+
+               acpi_rs_dump_resource_list(ACPI_CAST_PTR
+                                          (struct acpi_resource,
+                                           acpi_gbl_db_buffer));
+       }
+
+       /* _AEI */
+
+get_aei:
+       if (aei_node) {
+               acpi_os_printf("Evaluating _AEI\n");
+
+               return_buffer.pointer = acpi_gbl_db_buffer;
+               return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+               status =
+                   acpi_evaluate_object(aei_node, NULL, NULL, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not evaluate _AEI: %s\n",
+                                      acpi_format_exception(status));
+                       goto cleanup;
+               }
+
+               return_buffer.pointer = acpi_gbl_db_buffer;
+               return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+               status = acpi_get_event_resources(node, &return_buffer);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiGetEventResources failed: %s\n",
+                                      acpi_format_exception(status));
+                       goto cleanup;
+               }
+
+               acpi_rs_dump_resource_list(ACPI_CAST_PTR
+                                          (struct acpi_resource,
+                                           acpi_gbl_db_buffer));
+       }
+
+cleanup:
+       ACPI_FREE(parent_path);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_resources
+ *
+ * PARAMETERS:  object_arg          - String object name or object pointer.
+ *                                    NULL or "*" means "display resources for
+ *                                    all devices"
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the resource objects associated with a device.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_resources(char *object_arg)
+{
+       struct acpi_namespace_node *node;
+
+       acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+       acpi_dbg_level |= ACPI_LV_RESOURCES;
+
+       /* Asterisk means "display resources for all devices" */
+
+       if (!object_arg || (!strcmp(object_arg, "*"))) {
+               (void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                                         ACPI_UINT32_MAX,
+                                         acpi_db_device_resources, NULL, NULL,
+                                         NULL);
+       } else {
+               /* Convert string to object pointer */
+
+               node = acpi_db_convert_to_node(object_arg);
+               if (node) {
+                       if (node->type != ACPI_TYPE_DEVICE) {
+                               acpi_os_printf
+                                   ("%4.4s: Name is not a device object (%s)\n",
+                                    node->name.ascii,
+                                    acpi_ut_get_type_name(node->type));
+                       } else {
+                               (void)acpi_db_device_resources(node, 0, NULL,
+                                                              NULL);
+                       }
+               }
+       }
+
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_generate_gpe
+ *
+ * PARAMETERS:  gpe_arg             - Raw GPE number, ascii string
+ *              block_arg           - GPE block number, ascii string
+ *                                    0 or 1 for FADT GPE blocks
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate firing of a GPE
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)
+{
+       u32 block_number = 0;
+       u32 gpe_number;
+       struct acpi_gpe_event_info *gpe_event_info;
+
+       gpe_number = strtoul(gpe_arg, NULL, 0);
+
+       /*
+        * If no block arg, or block arg == 0 or 1, use the FADT-defined
+        * GPE blocks.
+        */
+       if (block_arg) {
+               block_number = strtoul(block_arg, NULL, 0);
+               if (block_number == 1) {
+                       block_number = 0;
+               }
+       }
+
+       gpe_event_info =
+           acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number),
+                                      gpe_number);
+       if (!gpe_event_info) {
+               acpi_os_printf("Invalid GPE\n");
+               return;
+       }
+
+       (void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_generate_sci
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate an SCI -- just call the SCI dispatch.
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_sci(void)
+{
+       acpi_ev_sci_dispatch();
+}
+
+#endif                         /* !ACPI_REDUCED_HARDWARE */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_trace
+ *
+ * PARAMETERS:  enable_arg          - ENABLE/AML to enable tracer
+ *                                    DISABLE to disable tracer
+ *              method_arg          - Method to trace
+ *              once_arg            - Whether trace once
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Control method tracing facility
+ *
+ ******************************************************************************/
+
+void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg)
+{
+       u32 debug_level = 0;
+       u32 debug_layer = 0;
+       u32 flags = 0;
+
+       if (enable_arg) {
+               acpi_ut_strupr(enable_arg);
+       }
+
+       if (once_arg) {
+               acpi_ut_strupr(once_arg);
+       }
+
+       if (method_arg) {
+               if (acpi_db_trace_method_name) {
+                       ACPI_FREE(acpi_db_trace_method_name);
+                       acpi_db_trace_method_name = NULL;
+               }
+
+               acpi_db_trace_method_name =
+                   ACPI_ALLOCATE(strlen(method_arg) + 1);
+               if (!acpi_db_trace_method_name) {
+                       acpi_os_printf("Failed to allocate method name (%s)\n",
+                                      method_arg);
+                       return;
+               }
+
+               strcpy(acpi_db_trace_method_name, method_arg);
+       }
+
+       if (!strcmp(enable_arg, "ENABLE") ||
+           !strcmp(enable_arg, "METHOD") || !strcmp(enable_arg, "OPCODE")) {
+               if (!strcmp(enable_arg, "ENABLE")) {
+
+                       /* Inherit current console settings */
+
+                       debug_level = acpi_gbl_db_console_debug_level;
+                       debug_layer = acpi_dbg_layer;
+               } else {
+                       /* Restrict console output to trace points only */
+
+                       debug_level = ACPI_LV_TRACE_POINT;
+                       debug_layer = ACPI_EXECUTER;
+               }
+
+               flags = ACPI_TRACE_ENABLED;
+
+               if (!strcmp(enable_arg, "OPCODE")) {
+                       flags |= ACPI_TRACE_OPCODE;
+               }
+
+               if (once_arg && !strcmp(once_arg, "ONCE")) {
+                       flags |= ACPI_TRACE_ONESHOT;
+               }
+       }
+
+       (void)acpi_debug_trace(acpi_db_trace_method_name,
+                              debug_level, debug_layer, flags);
+}
diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
new file mode 100644 (file)
index 0000000..a71632c
--- /dev/null
@@ -0,0 +1,484 @@
+/*******************************************************************************
+ *
+ * Module Name: dbconvert - debugger miscellaneous conversion routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbconvert")
+
+#define DB_DEFAULT_PKG_ELEMENTS     33
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_hex_char_to_value
+ *
+ * PARAMETERS:  hex_char            - Ascii Hex digit, 0-9|a-f|A-F
+ *              return_value        - Where the converted value is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16).
+ *
+ ******************************************************************************/
+acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value)
+{
+       u8 value;
+
+       /* Digit must be ascii [0-9a-fA-F] */
+
+       if (!isxdigit(hex_char)) {
+               return (AE_BAD_HEX_CONSTANT);
+       }
+
+       if (hex_char <= 0x39) {
+               value = (u8)(hex_char - 0x30);
+       } else {
+               value = (u8)(toupper(hex_char) - 0x37);
+       }
+
+       *return_value = value;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_hex_byte_to_binary
+ *
+ * PARAMETERS:  hex_byte            - Double hex digit (0x00 - 0xFF) in format:
+ *                                    hi_byte then lo_byte.
+ *              return_value        - Where the converted value is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255).
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_db_hex_byte_to_binary(char *hex_byte, u8 *return_value)
+{
+       u8 local0;
+       u8 local1;
+       acpi_status status;
+
+       /* High byte */
+
+       status = acpi_db_hex_char_to_value(hex_byte[0], &local0);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Low byte */
+
+       status = acpi_db_hex_char_to_value(hex_byte[1], &local1);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       *return_value = (u8)((local0 << 4) | local1);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_buffer
+ *
+ * PARAMETERS:  string              - Input string to be converted
+ *              object              - Where the buffer object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a string to a buffer object. String is treated a list
+ *              of buffer elements, each separated by a space or comma.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_convert_to_buffer(char *string, union acpi_object *object)
+{
+       u32 i;
+       u32 j;
+       u32 length;
+       u8 *buffer;
+       acpi_status status;
+
+       /* Generate the final buffer length */
+
+       for (i = 0, length = 0; string[i];) {
+               i += 2;
+               length++;
+
+               while (string[i] && ((string[i] == ',') || (string[i] == ' '))) {
+                       i++;
+               }
+       }
+
+       buffer = ACPI_ALLOCATE(length);
+       if (!buffer) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Convert the command line bytes to the buffer */
+
+       for (i = 0, j = 0; string[i];) {
+               status = acpi_db_hex_byte_to_binary(&string[i], &buffer[j]);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_FREE(buffer);
+                       return (status);
+               }
+
+               j++;
+               i += 2;
+               while (string[i] && ((string[i] == ',') || (string[i] == ' '))) {
+                       i++;
+               }
+       }
+
+       object->type = ACPI_TYPE_BUFFER;
+       object->buffer.pointer = buffer;
+       object->buffer.length = length;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_package
+ *
+ * PARAMETERS:  string              - Input string to be converted
+ *              object              - Where the package object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a string to a package object. Handles nested packages
+ *              via recursion with acpi_db_convert_to_object.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_convert_to_package(char *string, union acpi_object * object)
+{
+       char *this;
+       char *next;
+       u32 i;
+       acpi_object_type type;
+       union acpi_object *elements;
+       acpi_status status;
+
+       elements =
+           ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
+                                sizeof(union acpi_object));
+
+       this = string;
+       for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
+               this = acpi_db_get_next_token(this, &next, &type);
+               if (!this) {
+                       break;
+               }
+
+               /* Recursive call to convert each package element */
+
+               status = acpi_db_convert_to_object(type, this, &elements[i]);
+               if (ACPI_FAILURE(status)) {
+                       acpi_db_delete_objects(i + 1, elements);
+                       ACPI_FREE(elements);
+                       return (status);
+               }
+
+               this = next;
+       }
+
+       object->type = ACPI_TYPE_PACKAGE;
+       object->package.count = i;
+       object->package.elements = elements;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_object
+ *
+ * PARAMETERS:  type                - Object type as determined by parser
+ *              string              - Input string to be converted
+ *              object              - Where the new object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a typed and tokenized string to an union acpi_object. Typing:
+ *              1) String objects were surrounded by quotes.
+ *              2) Buffer objects were surrounded by parentheses.
+ *              3) Package objects were surrounded by brackets "[]".
+ *              4) All standalone tokens are treated as integers.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_convert_to_object(acpi_object_type type,
+                         char *string, union acpi_object * object)
+{
+       acpi_status status = AE_OK;
+
+       switch (type) {
+       case ACPI_TYPE_STRING:
+
+               object->type = ACPI_TYPE_STRING;
+               object->string.pointer = string;
+               object->string.length = (u32)strlen(string);
+               break;
+
+       case ACPI_TYPE_BUFFER:
+
+               status = acpi_db_convert_to_buffer(string, object);
+               break;
+
+       case ACPI_TYPE_PACKAGE:
+
+               status = acpi_db_convert_to_package(string, object);
+               break;
+
+       default:
+
+               object->type = ACPI_TYPE_INTEGER;
+               status = acpi_ut_strtoul64(string, 16, &object->integer.value);
+               break;
+       }
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_encode_pld_buffer
+ *
+ * PARAMETERS:  pld_info            - _PLD buffer struct (Using local struct)
+ *
+ * RETURN:      Encode _PLD buffer suitable for return value from _PLD
+ *
+ * DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros
+ *
+ ******************************************************************************/
+
+u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info)
+{
+       u32 *buffer;
+       u32 dword;
+
+       buffer = ACPI_ALLOCATE_ZEROED(ACPI_PLD_BUFFER_SIZE);
+       if (!buffer) {
+               return (NULL);
+       }
+
+       /* First 32 bits */
+
+       dword = 0;
+       ACPI_PLD_SET_REVISION(&dword, pld_info->revision);
+       ACPI_PLD_SET_IGNORE_COLOR(&dword, pld_info->ignore_color);
+       ACPI_PLD_SET_RED(&dword, pld_info->red);
+       ACPI_PLD_SET_GREEN(&dword, pld_info->green);
+       ACPI_PLD_SET_BLUE(&dword, pld_info->blue);
+       ACPI_MOVE_32_TO_32(&buffer[0], &dword);
+
+       /* Second 32 bits */
+
+       dword = 0;
+       ACPI_PLD_SET_WIDTH(&dword, pld_info->width);
+       ACPI_PLD_SET_HEIGHT(&dword, pld_info->height);
+       ACPI_MOVE_32_TO_32(&buffer[1], &dword);
+
+       /* Third 32 bits */
+
+       dword = 0;
+       ACPI_PLD_SET_USER_VISIBLE(&dword, pld_info->user_visible);
+       ACPI_PLD_SET_DOCK(&dword, pld_info->dock);
+       ACPI_PLD_SET_LID(&dword, pld_info->lid);
+       ACPI_PLD_SET_PANEL(&dword, pld_info->panel);
+       ACPI_PLD_SET_VERTICAL(&dword, pld_info->vertical_position);
+       ACPI_PLD_SET_HORIZONTAL(&dword, pld_info->horizontal_position);
+       ACPI_PLD_SET_SHAPE(&dword, pld_info->shape);
+       ACPI_PLD_SET_ORIENTATION(&dword, pld_info->group_orientation);
+       ACPI_PLD_SET_TOKEN(&dword, pld_info->group_token);
+       ACPI_PLD_SET_POSITION(&dword, pld_info->group_position);
+       ACPI_PLD_SET_BAY(&dword, pld_info->bay);
+       ACPI_MOVE_32_TO_32(&buffer[2], &dword);
+
+       /* Fourth 32 bits */
+
+       dword = 0;
+       ACPI_PLD_SET_EJECTABLE(&dword, pld_info->ejectable);
+       ACPI_PLD_SET_OSPM_EJECT(&dword, pld_info->ospm_eject_required);
+       ACPI_PLD_SET_CABINET(&dword, pld_info->cabinet_number);
+       ACPI_PLD_SET_CARD_CAGE(&dword, pld_info->card_cage_number);
+       ACPI_PLD_SET_REFERENCE(&dword, pld_info->reference);
+       ACPI_PLD_SET_ROTATION(&dword, pld_info->rotation);
+       ACPI_PLD_SET_ORDER(&dword, pld_info->order);
+       ACPI_MOVE_32_TO_32(&buffer[3], &dword);
+
+       if (pld_info->revision >= 2) {
+
+               /* Fifth 32 bits */
+
+               dword = 0;
+               ACPI_PLD_SET_VERT_OFFSET(&dword, pld_info->vertical_offset);
+               ACPI_PLD_SET_HORIZ_OFFSET(&dword, pld_info->horizontal_offset);
+               ACPI_MOVE_32_TO_32(&buffer[4], &dword);
+       }
+
+       return (ACPI_CAST_PTR(u8, buffer));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_pld_buffer
+ *
+ * PARAMETERS:  obj_desc            - Object returned from _PLD method
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Dumps formatted contents of a _PLD return buffer.
+ *
+ ******************************************************************************/
+
+#define ACPI_PLD_OUTPUT     "%20s : %-6X\n"
+
+void acpi_db_dump_pld_buffer(union acpi_object *obj_desc)
+{
+       union acpi_object *buffer_desc;
+       struct acpi_pld_info *pld_info;
+       u8 *new_buffer;
+       acpi_status status;
+
+       /* Object must be of type Package with at least one Buffer element */
+
+       if (obj_desc->type != ACPI_TYPE_PACKAGE) {
+               return;
+       }
+
+       buffer_desc = &obj_desc->package.elements[0];
+       if (buffer_desc->type != ACPI_TYPE_BUFFER) {
+               return;
+       }
+
+       /* Convert _PLD buffer to local _PLD struct */
+
+       status = acpi_decode_pld_buffer(buffer_desc->buffer.pointer,
+                                       buffer_desc->buffer.length, &pld_info);
+       if (ACPI_FAILURE(status)) {
+               return;
+       }
+
+       /* Encode local _PLD struct back to a _PLD buffer */
+
+       new_buffer = acpi_db_encode_pld_buffer(pld_info);
+       if (!new_buffer) {
+               return;
+       }
+
+       /* The two bit-packed buffers should match */
+
+       if (memcmp(new_buffer, buffer_desc->buffer.pointer,
+                  buffer_desc->buffer.length)) {
+               acpi_os_printf
+                   ("Converted _PLD buffer does not compare. New:\n");
+
+               acpi_ut_dump_buffer(new_buffer,
+                                   buffer_desc->buffer.length, DB_BYTE_DISPLAY,
+                                   0);
+       }
+
+       /* First 32-bit dword */
+
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Revision", pld_info->revision);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_IgnoreColor",
+                      pld_info->ignore_color);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Red", pld_info->red);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Green", pld_info->green);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Blue", pld_info->blue);
+
+       /* Second 32-bit dword */
+
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Width", pld_info->width);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Height", pld_info->height);
+
+       /* Third 32-bit dword */
+
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_UserVisible",
+                      pld_info->user_visible);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Dock", pld_info->dock);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Lid", pld_info->lid);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Panel", pld_info->panel);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalPosition",
+                      pld_info->vertical_position);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalPosition",
+                      pld_info->horizontal_position);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Shape", pld_info->shape);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupOrientation",
+                      pld_info->group_orientation);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupToken",
+                      pld_info->group_token);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupPosition",
+                      pld_info->group_position);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Bay", pld_info->bay);
+
+       /* Fourth 32-bit dword */
+
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Ejectable", pld_info->ejectable);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_EjectRequired",
+                      pld_info->ospm_eject_required);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CabinetNumber",
+                      pld_info->cabinet_number);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CardCageNumber",
+                      pld_info->card_cage_number);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Reference", pld_info->reference);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Rotation", pld_info->rotation);
+       acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Order", pld_info->order);
+
+       /* Fifth 32-bit dword */
+
+       if (buffer_desc->buffer.length > 16) {
+               acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalOffset",
+                              pld_info->vertical_offset);
+               acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalOffset",
+                              pld_info->horizontal_offset);
+       }
+
+       ACPI_FREE(pld_info);
+       ACPI_FREE(new_buffer);
+}
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
new file mode 100644 (file)
index 0000000..672977e
--- /dev/null
@@ -0,0 +1,1108 @@
+/*******************************************************************************
+ *
+ * Module Name: dbdisply - debug display commands
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acparser.h"
+#include "acinterp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbdisply")
+
+/* Local prototypes */
+static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op);
+
+static void *acpi_db_get_pointer(void *target);
+
+static acpi_status
+acpi_db_display_non_root_handlers(acpi_handle obj_handle,
+                                 u32 nesting_level,
+                                 void *context, void **return_value);
+
+/*
+ * System handler information.
+ * Used for Handlers command, in acpi_db_display_handlers.
+ */
+#define ACPI_PREDEFINED_PREFIX          "%25s (%.2X) : "
+#define ACPI_HANDLER_NAME_STRING               "%30s : "
+#define ACPI_HANDLER_PRESENT_STRING                    "%-9s (%p)\n"
+#define ACPI_HANDLER_PRESENT_STRING2                   "%-9s (%p)"
+#define ACPI_HANDLER_NOT_PRESENT_STRING                "%-9s\n"
+
+/* All predefined Address Space IDs */
+
+static acpi_adr_space_type acpi_gbl_space_id_list[] = {
+       ACPI_ADR_SPACE_SYSTEM_MEMORY,
+       ACPI_ADR_SPACE_SYSTEM_IO,
+       ACPI_ADR_SPACE_PCI_CONFIG,
+       ACPI_ADR_SPACE_EC,
+       ACPI_ADR_SPACE_SMBUS,
+       ACPI_ADR_SPACE_CMOS,
+       ACPI_ADR_SPACE_PCI_BAR_TARGET,
+       ACPI_ADR_SPACE_IPMI,
+       ACPI_ADR_SPACE_GPIO,
+       ACPI_ADR_SPACE_GSBUS,
+       ACPI_ADR_SPACE_DATA_TABLE,
+       ACPI_ADR_SPACE_FIXED_HARDWARE
+};
+
+/* Global handler information */
+
+typedef struct acpi_handler_info {
+       void *handler;
+       char *name;
+
+} acpi_handler_info;
+
+static struct acpi_handler_info acpi_gbl_handler_list[] = {
+       {&acpi_gbl_global_notify[0].handler, "System Notifications"},
+       {&acpi_gbl_global_notify[1].handler, "Device Notifications"},
+       {&acpi_gbl_table_handler, "ACPI Table Events"},
+       {&acpi_gbl_exception_handler, "Control Method Exceptions"},
+       {&acpi_gbl_interface_handler, "OSI Invocations"}
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_pointer
+ *
+ * PARAMETERS:  target          - Pointer to string to be converted
+ *
+ * RETURN:      Converted pointer
+ *
+ * DESCRIPTION: Convert an ascii pointer value to a real value
+ *
+ ******************************************************************************/
+
+static void *acpi_db_get_pointer(void *target)
+{
+       void *obj_ptr;
+       acpi_size address;
+
+       address = strtoul(target, NULL, 16);
+       obj_ptr = ACPI_TO_POINTER(address);
+       return (obj_ptr);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_parser_descriptor
+ *
+ * PARAMETERS:  op              - A parser Op descriptor
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display a formatted parser object
+ *
+ ******************************************************************************/
+
+static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op)
+{
+       const struct acpi_opcode_info *info;
+
+       info = acpi_ps_get_opcode_info(op->common.aml_opcode);
+
+       acpi_os_printf("Parser Op Descriptor:\n");
+       acpi_os_printf("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode);
+
+       ACPI_DEBUG_ONLY_MEMBERS(acpi_os_printf("%20.20s : %s\n", "Opcode Name",
+                                              info->name));
+
+       acpi_os_printf("%20.20s : %p\n", "Value/ArgList", op->common.value.arg);
+       acpi_os_printf("%20.20s : %p\n", "Parent", op->common.parent);
+       acpi_os_printf("%20.20s : %p\n", "NextOp", op->common.next);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_and_display_object
+ *
+ * PARAMETERS:  target          - String with object to be displayed. Names
+ *                                and hex pointers are supported.
+ *              output_type     - Byte, Word, Dword, or Qword (B|W|D|Q)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display a formatted ACPI object
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_and_display_object(char *target, char *output_type)
+{
+       void *obj_ptr;
+       struct acpi_namespace_node *node;
+       union acpi_operand_object *obj_desc;
+       u32 display = DB_BYTE_DISPLAY;
+       char buffer[80];
+       struct acpi_buffer ret_buf;
+       acpi_status status;
+       u32 size;
+
+       if (!target) {
+               return;
+       }
+
+       /* Decode the output type */
+
+       if (output_type) {
+               acpi_ut_strupr(output_type);
+               if (output_type[0] == 'W') {
+                       display = DB_WORD_DISPLAY;
+               } else if (output_type[0] == 'D') {
+                       display = DB_DWORD_DISPLAY;
+               } else if (output_type[0] == 'Q') {
+                       display = DB_QWORD_DISPLAY;
+               }
+       }
+
+       ret_buf.length = sizeof(buffer);
+       ret_buf.pointer = buffer;
+
+       /* Differentiate between a number and a name */
+
+       if ((target[0] >= 0x30) && (target[0] <= 0x39)) {
+               obj_ptr = acpi_db_get_pointer(target);
+               if (!acpi_os_readable(obj_ptr, 16)) {
+                       acpi_os_printf
+                           ("Address %p is invalid in this address space\n",
+                            obj_ptr);
+                       return;
+               }
+
+               /* Decode the object type */
+
+               switch (ACPI_GET_DESCRIPTOR_TYPE(obj_ptr)) {
+               case ACPI_DESC_TYPE_NAMED:
+
+                       /* This is a namespace Node */
+
+                       if (!acpi_os_readable
+                           (obj_ptr, sizeof(struct acpi_namespace_node))) {
+                               acpi_os_printf
+                                   ("Cannot read entire Named object at address %p\n",
+                                    obj_ptr);
+                               return;
+                       }
+
+                       node = obj_ptr;
+                       goto dump_node;
+
+               case ACPI_DESC_TYPE_OPERAND:
+
+                       /* This is a ACPI OPERAND OBJECT */
+
+                       if (!acpi_os_readable
+                           (obj_ptr, sizeof(union acpi_operand_object))) {
+                               acpi_os_printf
+                                   ("Cannot read entire ACPI object at address %p\n",
+                                    obj_ptr);
+                               return;
+                       }
+
+                       acpi_ut_debug_dump_buffer(obj_ptr,
+                                                 sizeof(union
+                                                        acpi_operand_object),
+                                                 display, ACPI_UINT32_MAX);
+                       acpi_ex_dump_object_descriptor(obj_ptr, 1);
+                       break;
+
+               case ACPI_DESC_TYPE_PARSER:
+
+                       /* This is a Parser Op object */
+
+                       if (!acpi_os_readable
+                           (obj_ptr, sizeof(union acpi_parse_object))) {
+                               acpi_os_printf
+                                   ("Cannot read entire Parser object at address %p\n",
+                                    obj_ptr);
+                               return;
+                       }
+
+                       acpi_ut_debug_dump_buffer(obj_ptr,
+                                                 sizeof(union
+                                                        acpi_parse_object),
+                                                 display, ACPI_UINT32_MAX);
+                       acpi_db_dump_parser_descriptor((union acpi_parse_object
+                                                       *)obj_ptr);
+                       break;
+
+               default:
+
+                       /* Is not a recognizeable object */
+
+                       acpi_os_printf
+                           ("Not a known ACPI internal object, descriptor type %2.2X\n",
+                            ACPI_GET_DESCRIPTOR_TYPE(obj_ptr));
+
+                       size = 16;
+                       if (acpi_os_readable(obj_ptr, 64)) {
+                               size = 64;
+                       }
+
+                       /* Just dump some memory */
+
+                       acpi_ut_debug_dump_buffer(obj_ptr, size, display,
+                                                 ACPI_UINT32_MAX);
+                       break;
+               }
+
+               return;
+       }
+
+       /* The parameter is a name string that must be resolved to a Named obj */
+
+       node = acpi_db_local_ns_lookup(target);
+       if (!node) {
+               return;
+       }
+
+dump_node:
+       /* Now dump the NS node */
+
+       status = acpi_get_name(node, ACPI_FULL_PATHNAME_NO_TRAILING, &ret_buf);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not convert name to pathname\n");
+       }
+
+       else {
+               acpi_os_printf("Object (%p) Pathname: %s\n",
+                              node, (char *)ret_buf.pointer);
+       }
+
+       if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
+               acpi_os_printf("Invalid Named object at address %p\n", node);
+               return;
+       }
+
+       acpi_ut_debug_dump_buffer((void *)node,
+                                 sizeof(struct acpi_namespace_node), display,
+                                 ACPI_UINT32_MAX);
+       acpi_ex_dump_namespace_node(node, 1);
+
+       obj_desc = acpi_ns_get_attached_object(node);
+       if (obj_desc) {
+               acpi_os_printf("\nAttached Object (%p):\n", obj_desc);
+               if (!acpi_os_readable
+                   (obj_desc, sizeof(union acpi_operand_object))) {
+                       acpi_os_printf
+                           ("Invalid internal ACPI Object at address %p\n",
+                            obj_desc);
+                       return;
+               }
+
+               acpi_ut_debug_dump_buffer((void *)obj_desc,
+                                         sizeof(union acpi_operand_object),
+                                         display, ACPI_UINT32_MAX);
+               acpi_ex_dump_object_descriptor(obj_desc, 1);
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_method_info
+ *
+ * PARAMETERS:  start_op        - Root of the control method parse tree
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about the current method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_method_info(union acpi_parse_object *start_op)
+{
+       struct acpi_walk_state *walk_state;
+       union acpi_operand_object *obj_desc;
+       struct acpi_namespace_node *node;
+       union acpi_parse_object *root_op;
+       union acpi_parse_object *op;
+       const struct acpi_opcode_info *op_info;
+       u32 num_ops = 0;
+       u32 num_operands = 0;
+       u32 num_operators = 0;
+       u32 num_remaining_ops = 0;
+       u32 num_remaining_operands = 0;
+       u32 num_remaining_operators = 0;
+       u8 count_remaining = FALSE;
+
+       walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+       if (!walk_state) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       obj_desc = walk_state->method_desc;
+       node = walk_state->method_node;
+
+       acpi_os_printf("Currently executing control method is [%4.4s]\n",
+                      acpi_ut_get_node_name(node));
+       acpi_os_printf("%X Arguments, SyncLevel = %X\n",
+                      (u32)obj_desc->method.param_count,
+                      (u32)obj_desc->method.sync_level);
+
+       root_op = start_op;
+       while (root_op->common.parent) {
+               root_op = root_op->common.parent;
+       }
+
+       op = root_op;
+
+       while (op) {
+               if (op == start_op) {
+                       count_remaining = TRUE;
+               }
+
+               num_ops++;
+               if (count_remaining) {
+                       num_remaining_ops++;
+               }
+
+               /* Decode the opcode */
+
+               op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
+               switch (op_info->class) {
+               case AML_CLASS_ARGUMENT:
+
+                       if (count_remaining) {
+                               num_remaining_operands++;
+                       }
+
+                       num_operands++;
+                       break;
+
+               case AML_CLASS_UNKNOWN:
+
+                       /* Bad opcode or ASCII character */
+
+                       continue;
+
+               default:
+
+                       if (count_remaining) {
+                               num_remaining_operators++;
+                       }
+
+                       num_operators++;
+                       break;
+               }
+
+               op = acpi_ps_get_depth_next(start_op, op);
+       }
+
+       acpi_os_printf
+           ("Method contains:       %X AML Opcodes - %X Operators, %X Operands\n",
+            num_ops, num_operators, num_operands);
+
+       acpi_os_printf
+           ("Remaining to execute:  %X AML Opcodes - %X Operators, %X Operands\n",
+            num_remaining_ops, num_remaining_operators,
+            num_remaining_operands);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_locals
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all locals for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_locals(void)
+{
+       struct acpi_walk_state *walk_state;
+
+       walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+       if (!walk_state) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       acpi_db_decode_locals(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_arguments
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all arguments for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_arguments(void)
+{
+       struct acpi_walk_state *walk_state;
+
+       walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+       if (!walk_state) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       acpi_db_decode_arguments(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_results
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display current contents of a method result stack
+ *
+ ******************************************************************************/
+
+void acpi_db_display_results(void)
+{
+       u32 i;
+       struct acpi_walk_state *walk_state;
+       union acpi_operand_object *obj_desc;
+       u32 result_count = 0;
+       struct acpi_namespace_node *node;
+       union acpi_generic_state *frame;
+       u32 index;              /* Index onto current frame */
+
+       walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+       if (!walk_state) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       obj_desc = walk_state->method_desc;
+       node = walk_state->method_node;
+
+       if (walk_state->results) {
+               result_count = walk_state->result_count;
+       }
+
+       acpi_os_printf("Method [%4.4s] has %X stacked result objects\n",
+                      acpi_ut_get_node_name(node), result_count);
+
+       /* From the top element of result stack */
+
+       frame = walk_state->results;
+       index = (result_count - 1) % ACPI_RESULTS_FRAME_OBJ_NUM;
+
+       for (i = 0; i < result_count; i++) {
+               obj_desc = frame->results.obj_desc[index];
+               acpi_os_printf("Result%u: ", i);
+               acpi_db_display_internal_object(obj_desc, walk_state);
+
+               if (index == 0) {
+                       frame = frame->results.next;
+                       index = ACPI_RESULTS_FRAME_OBJ_NUM;
+               }
+
+               index--;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_calling_tree
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display current calling tree of nested control methods
+ *
+ ******************************************************************************/
+
+void acpi_db_display_calling_tree(void)
+{
+       struct acpi_walk_state *walk_state;
+       struct acpi_namespace_node *node;
+
+       walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+       if (!walk_state) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       node = walk_state->method_node;
+       acpi_os_printf("Current Control Method Call Tree\n");
+
+       while (walk_state) {
+               node = walk_state->method_node;
+               acpi_os_printf("  [%4.4s]\n", acpi_ut_get_node_name(node));
+
+               walk_state = walk_state->next;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_object_type
+ *
+ * PARAMETERS:  name            - User entered NS node handle or name
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display type of an arbitrary NS node
+ *
+ ******************************************************************************/
+
+void acpi_db_display_object_type(char *name)
+{
+       struct acpi_namespace_node *node;
+       struct acpi_device_info *info;
+       acpi_status status;
+       u32 i;
+
+       node = acpi_db_convert_to_node(name);
+       if (!node) {
+               return;
+       }
+
+       status = acpi_get_object_info(ACPI_CAST_PTR(acpi_handle, node), &info);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not get object info, %s\n",
+                              acpi_format_exception(status));
+               return;
+       }
+
+       if (info->valid & ACPI_VALID_ADR) {
+               acpi_os_printf("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n",
+                              ACPI_FORMAT_UINT64(info->address),
+                              info->current_status, info->flags);
+       }
+       if (info->valid & ACPI_VALID_SXDS) {
+               acpi_os_printf("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n",
+                              info->highest_dstates[0],
+                              info->highest_dstates[1],
+                              info->highest_dstates[2],
+                              info->highest_dstates[3]);
+       }
+       if (info->valid & ACPI_VALID_SXWS) {
+               acpi_os_printf
+                   ("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n",
+                    info->lowest_dstates[0], info->lowest_dstates[1],
+                    info->lowest_dstates[2], info->lowest_dstates[3],
+                    info->lowest_dstates[4]);
+       }
+
+       if (info->valid & ACPI_VALID_HID) {
+               acpi_os_printf("HID: %s\n", info->hardware_id.string);
+       }
+
+       if (info->valid & ACPI_VALID_UID) {
+               acpi_os_printf("UID: %s\n", info->unique_id.string);
+       }
+
+       if (info->valid & ACPI_VALID_SUB) {
+               acpi_os_printf("SUB: %s\n", info->subsystem_id.string);
+       }
+
+       if (info->valid & ACPI_VALID_CID) {
+               for (i = 0; i < info->compatible_id_list.count; i++) {
+                       acpi_os_printf("CID %u: %s\n", i,
+                                      info->compatible_id_list.ids[i].string);
+               }
+       }
+
+       ACPI_FREE(info);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_result_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the result of an AML opcode
+ *
+ * Note: Curently only displays the result object if we are single stepping.
+ * However, this output may be useful in other contexts and could be enabled
+ * to do so if needed.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_result_object(union acpi_operand_object *obj_desc,
+                             struct acpi_walk_state *walk_state)
+{
+
+       /* Only display if single stepping */
+
+       if (!acpi_gbl_cm_single_step) {
+               return;
+       }
+
+       acpi_os_printf("ResultObj: ");
+       acpi_db_display_internal_object(obj_desc, walk_state);
+       acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_argument_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the result of an AML opcode
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
+                               struct acpi_walk_state *walk_state)
+{
+
+       if (!acpi_gbl_cm_single_step) {
+               return;
+       }
+
+       acpi_os_printf("ArgObj:  ");
+       acpi_db_display_internal_object(obj_desc, walk_state);
+}
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_gpes
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the current GPE structures
+ *
+ ******************************************************************************/
+
+void acpi_db_display_gpes(void)
+{
+       struct acpi_gpe_block_info *gpe_block;
+       struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+       struct acpi_gpe_event_info *gpe_event_info;
+       struct acpi_gpe_register_info *gpe_register_info;
+       char *gpe_type;
+       struct acpi_gpe_notify_info *notify;
+       u32 gpe_index;
+       u32 block = 0;
+       u32 i;
+       u32 j;
+       u32 count;
+       char buffer[80];
+       struct acpi_buffer ret_buf;
+       acpi_status status;
+
+       ret_buf.length = sizeof(buffer);
+       ret_buf.pointer = buffer;
+
+       block = 0;
+
+       /* Walk the GPE lists */
+
+       gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+       while (gpe_xrupt_info) {
+               gpe_block = gpe_xrupt_info->gpe_block_list_head;
+               while (gpe_block) {
+                       status = acpi_get_name(gpe_block->node,
+                                              ACPI_FULL_PATHNAME_NO_TRAILING,
+                                              &ret_buf);
+                       if (ACPI_FAILURE(status)) {
+                               acpi_os_printf
+                                   ("Could not convert name to pathname\n");
+                       }
+
+                       if (gpe_block->node == acpi_gbl_fadt_gpe_device) {
+                               gpe_type = "FADT-defined GPE block";
+                       } else {
+                               gpe_type = "GPE Block Device";
+                       }
+
+                       acpi_os_printf
+                           ("\nBlock %u - Info %p  DeviceNode %p [%s] - %s\n",
+                            block, gpe_block, gpe_block->node, buffer,
+                            gpe_type);
+
+                       acpi_os_printf("    Registers:    %u (%u GPEs)\n",
+                                      gpe_block->register_count,
+                                      gpe_block->gpe_count);
+
+                       acpi_os_printf
+                           ("    GPE range:    0x%X to 0x%X on interrupt %u\n",
+                            gpe_block->block_base_number,
+                            gpe_block->block_base_number +
+                            (gpe_block->gpe_count - 1),
+                            gpe_xrupt_info->interrupt_number);
+
+                       acpi_os_printf
+                           ("    RegisterInfo: %p  Status %8.8X%8.8X Enable %8.8X%8.8X\n",
+                            gpe_block->register_info,
+                            ACPI_FORMAT_UINT64(gpe_block->register_info->
+                                               status_address.address),
+                            ACPI_FORMAT_UINT64(gpe_block->register_info->
+                                               enable_address.address));
+
+                       acpi_os_printf("  EventInfo:    %p\n",
+                                      gpe_block->event_info);
+
+                       /* Examine each GPE Register within the block */
+
+                       for (i = 0; i < gpe_block->register_count; i++) {
+                               gpe_register_info =
+                                   &gpe_block->register_info[i];
+
+                               acpi_os_printf("    Reg %u: (GPE %.2X-%.2X)  "
+                                              "RunEnable %2.2X WakeEnable %2.2X"
+                                              " Status %8.8X%8.8X Enable %8.8X%8.8X\n",
+                                              i,
+                                              gpe_register_info->
+                                              base_gpe_number,
+                                              gpe_register_info->
+                                              base_gpe_number +
+                                              (ACPI_GPE_REGISTER_WIDTH - 1),
+                                              gpe_register_info->
+                                              enable_for_run,
+                                              gpe_register_info->
+                                              enable_for_wake,
+                                              ACPI_FORMAT_UINT64
+                                              (gpe_register_info->
+                                               status_address.address),
+                                              ACPI_FORMAT_UINT64
+                                              (gpe_register_info->
+                                               enable_address.address));
+
+                               /* Now look at the individual GPEs in this byte register */
+
+                               for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+                                       gpe_index =
+                                           (i * ACPI_GPE_REGISTER_WIDTH) + j;
+                                       gpe_event_info =
+                                           &gpe_block->event_info[gpe_index];
+
+                                       if (ACPI_GPE_DISPATCH_TYPE
+                                           (gpe_event_info->flags) ==
+                                           ACPI_GPE_DISPATCH_NONE) {
+
+                                               /* This GPE is not used (no method or handler), ignore it */
+
+                                               continue;
+                                       }
+
+                                       acpi_os_printf
+                                           ("        GPE %.2X: %p  RunRefs %2.2X Flags %2.2X (",
+                                            gpe_block->block_base_number +
+                                            gpe_index, gpe_event_info,
+                                            gpe_event_info->runtime_count,
+                                            gpe_event_info->flags);
+
+                                       /* Decode the flags byte */
+
+                                       if (gpe_event_info->
+                                           flags & ACPI_GPE_LEVEL_TRIGGERED) {
+                                               acpi_os_printf("Level, ");
+                                       } else {
+                                               acpi_os_printf("Edge, ");
+                                       }
+
+                                       if (gpe_event_info->
+                                           flags & ACPI_GPE_CAN_WAKE) {
+                                               acpi_os_printf("CanWake, ");
+                                       } else {
+                                               acpi_os_printf("RunOnly, ");
+                                       }
+
+                                       switch (ACPI_GPE_DISPATCH_TYPE
+                                               (gpe_event_info->flags)) {
+                                       case ACPI_GPE_DISPATCH_NONE:
+
+                                               acpi_os_printf("NotUsed");
+                                               break;
+
+                                       case ACPI_GPE_DISPATCH_METHOD:
+
+                                               acpi_os_printf("Method");
+                                               break;
+
+                                       case ACPI_GPE_DISPATCH_HANDLER:
+
+                                               acpi_os_printf("Handler");
+                                               break;
+
+                                       case ACPI_GPE_DISPATCH_NOTIFY:
+
+                                               count = 0;
+                                               notify =
+                                                   gpe_event_info->dispatch.
+                                                   notify_list;
+                                               while (notify) {
+                                                       count++;
+                                                       notify = notify->next;
+                                               }
+
+                                               acpi_os_printf
+                                                   ("Implicit Notify on %u devices",
+                                                    count);
+                                               break;
+
+                                       case ACPI_GPE_DISPATCH_RAW_HANDLER:
+
+                                               acpi_os_printf("RawHandler");
+                                               break;
+
+                                       default:
+
+                                               acpi_os_printf("UNKNOWN: %X",
+                                                              ACPI_GPE_DISPATCH_TYPE
+                                                              (gpe_event_info->
+                                                               flags));
+                                               break;
+                                       }
+
+                                       acpi_os_printf(")\n");
+                               }
+                       }
+
+                       block++;
+                       gpe_block = gpe_block->next;
+               }
+
+               gpe_xrupt_info = gpe_xrupt_info->next;
+       }
+}
+#endif                         /* !ACPI_REDUCED_HARDWARE */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_handlers
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the currently installed global handlers
+ *
+ ******************************************************************************/
+
+void acpi_db_display_handlers(void)
+{
+       union acpi_operand_object *obj_desc;
+       union acpi_operand_object *handler_obj;
+       acpi_adr_space_type space_id;
+       u32 i;
+
+       /* Operation region handlers */
+
+       acpi_os_printf("\nOperation Region Handlers at the namespace root:\n");
+
+       obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node);
+       if (obj_desc) {
+               for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_space_id_list); i++) {
+                       space_id = acpi_gbl_space_id_list[i];
+                       handler_obj = obj_desc->device.handler;
+
+                       acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+                                      acpi_ut_get_region_name((u8)space_id),
+                                      space_id);
+
+                       while (handler_obj) {
+                               if (acpi_gbl_space_id_list[i] ==
+                                   handler_obj->address_space.space_id) {
+                                       acpi_os_printf
+                                           (ACPI_HANDLER_PRESENT_STRING,
+                                            (handler_obj->address_space.
+                                             handler_flags &
+                                             ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
+                                            ? "Default" : "User",
+                                            handler_obj->address_space.
+                                            handler);
+
+                                       goto found_handler;
+                               }
+
+                               handler_obj = handler_obj->address_space.next;
+                       }
+
+                       /* There is no handler for this space_id */
+
+                       acpi_os_printf("None\n");
+
+found_handler:         ;
+               }
+
+               /* Find all handlers for user-defined space_IDs */
+
+               handler_obj = obj_desc->device.handler;
+               while (handler_obj) {
+                       if (handler_obj->address_space.space_id >=
+                           ACPI_USER_REGION_BEGIN) {
+                               acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+                                              "User-defined ID",
+                                              handler_obj->address_space.
+                                              space_id);
+                               acpi_os_printf(ACPI_HANDLER_PRESENT_STRING,
+                                              (handler_obj->address_space.
+                                               handler_flags &
+                                               ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
+                                              ? "Default" : "User",
+                                              handler_obj->address_space.
+                                              handler);
+                       }
+
+                       handler_obj = handler_obj->address_space.next;
+               }
+       }
+#if (!ACPI_REDUCED_HARDWARE)
+
+       /* Fixed event handlers */
+
+       acpi_os_printf("\nFixed Event Handlers:\n");
+
+       for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+               acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+                              acpi_ut_get_event_name(i), i);
+               if (acpi_gbl_fixed_event_handlers[i].handler) {
+                       acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User",
+                                      acpi_gbl_fixed_event_handlers[i].
+                                      handler);
+               } else {
+                       acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None");
+               }
+       }
+
+#endif                         /* !ACPI_REDUCED_HARDWARE */
+
+       /* Miscellaneous global handlers */
+
+       acpi_os_printf("\nMiscellaneous Global Handlers:\n");
+
+       for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_handler_list); i++) {
+               acpi_os_printf(ACPI_HANDLER_NAME_STRING,
+                              acpi_gbl_handler_list[i].name);
+
+               if (acpi_gbl_handler_list[i].handler) {
+                       acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User",
+                                      acpi_gbl_handler_list[i].handler);
+               } else {
+                       acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None");
+               }
+       }
+
+       /* Other handlers that are installed throughout the namespace */
+
+       acpi_os_printf("\nOperation Region Handlers for specific devices:\n");
+
+       (void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX,
+                                 acpi_db_display_non_root_handlers, NULL, NULL,
+                                 NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_non_root_handlers
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display information about all handlers installed for a
+ *              device object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_display_non_root_handlers(acpi_handle obj_handle,
+                                 u32 nesting_level,
+                                 void *context, void **return_value)
+{
+       struct acpi_namespace_node *node =
+           ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+       union acpi_operand_object *obj_desc;
+       union acpi_operand_object *handler_obj;
+       char *pathname;
+
+       obj_desc = acpi_ns_get_attached_object(node);
+       if (!obj_desc) {
+               return (AE_OK);
+       }
+
+       pathname = acpi_ns_get_external_pathname(node);
+       if (!pathname) {
+               return (AE_OK);
+       }
+
+       /* Display all handlers associated with this device */
+
+       handler_obj = obj_desc->device.handler;
+       while (handler_obj) {
+               acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+                              acpi_ut_get_region_name((u8)handler_obj->
+                                                      address_space.space_id),
+                              handler_obj->address_space.space_id);
+
+               acpi_os_printf(ACPI_HANDLER_PRESENT_STRING2,
+                              (handler_obj->address_space.handler_flags &
+                               ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default"
+                              : "User", handler_obj->address_space.handler);
+
+               acpi_os_printf(" Device Name: %s (%p)\n", pathname, node);
+
+               handler_obj = handler_obj->address_space.next;
+       }
+
+       ACPI_FREE(pathname);
+       return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
new file mode 100644 (file)
index 0000000..d713e2d
--- /dev/null
@@ -0,0 +1,764 @@
+/*******************************************************************************
+ *
+ * Module Name: dbexec - debugger control method execution
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbexec")
+
+static struct acpi_db_method_info acpi_gbl_db_method_info;
+
+/* Local prototypes */
+
+static acpi_status
+acpi_db_execute_method(struct acpi_db_method_info *info,
+                      struct acpi_buffer *return_obj);
+
+static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
+
+static u32 acpi_db_get_outstanding_allocations(void);
+
+static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
+
+static acpi_status
+acpi_db_execution_walk(acpi_handle obj_handle,
+                      u32 nesting_level, void *context, void **return_value);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_delete_objects
+ *
+ * PARAMETERS:  count               - Count of objects in the list
+ *              objects             - Array of ACPI_OBJECTs to be deleted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
+ *              packages via recursion.
+ *
+ ******************************************************************************/
+
+void acpi_db_delete_objects(u32 count, union acpi_object *objects)
+{
+       u32 i;
+
+       for (i = 0; i < count; i++) {
+               switch (objects[i].type) {
+               case ACPI_TYPE_BUFFER:
+
+                       ACPI_FREE(objects[i].buffer.pointer);
+                       break;
+
+               case ACPI_TYPE_PACKAGE:
+
+                       /* Recursive call to delete package elements */
+
+                       acpi_db_delete_objects(objects[i].package.count,
+                                              objects[i].package.elements);
+
+                       /* Free the elements array */
+
+                       ACPI_FREE(objects[i].package.elements);
+                       break;
+
+               default:
+
+                       break;
+               }
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_method
+ *
+ * PARAMETERS:  info            - Valid info segment
+ *              return_obj      - Where to put return object
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a control method.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_execute_method(struct acpi_db_method_info *info,
+                      struct acpi_buffer *return_obj)
+{
+       acpi_status status;
+       struct acpi_object_list param_objects;
+       union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
+       u32 i;
+
+       ACPI_FUNCTION_TRACE(db_execute_method);
+
+       if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
+               acpi_os_printf("Warning: debug output is not enabled!\n");
+       }
+
+       param_objects.count = 0;
+       param_objects.pointer = NULL;
+
+       /* Pass through any command-line arguments */
+
+       if (info->args && info->args[0]) {
+
+               /* Get arguments passed on the command line */
+
+               for (i = 0; (info->args[i] && *(info->args[i])); i++) {
+
+                       /* Convert input string (token) to an actual union acpi_object */
+
+                       status = acpi_db_convert_to_object(info->types[i],
+                                                          info->args[i],
+                                                          &params[i]);
+                       if (ACPI_FAILURE(status)) {
+                               ACPI_EXCEPTION((AE_INFO, status,
+                                               "While parsing method arguments"));
+                               goto cleanup;
+                       }
+               }
+
+               param_objects.count = i;
+               param_objects.pointer = params;
+       }
+
+       /* Prepare for a return object of arbitrary size */
+
+       return_obj->pointer = acpi_gbl_db_buffer;
+       return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
+
+       /* Do the actual method execution */
+
+       acpi_gbl_method_executing = TRUE;
+       status = acpi_evaluate_object(NULL, info->pathname,
+                                     &param_objects, return_obj);
+
+       acpi_gbl_cm_single_step = FALSE;
+       acpi_gbl_method_executing = FALSE;
+
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status,
+                               "while executing %s from debugger",
+                               info->pathname));
+
+               if (status == AE_BUFFER_OVERFLOW) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Possible overflow of internal debugger "
+                                   "buffer (size 0x%X needed 0x%X)",
+                                   ACPI_DEBUG_BUFFER_SIZE,
+                                   (u32)return_obj->length));
+               }
+       }
+
+cleanup:
+       acpi_db_delete_objects(param_objects.count, params);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_setup
+ *
+ * PARAMETERS:  info            - Valid method info
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Setup info segment prior to method execution
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_NAME(db_execute_setup);
+
+       /* Catenate the current scope to the supplied name */
+
+       info->pathname[0] = 0;
+       if ((info->name[0] != '\\') && (info->name[0] != '/')) {
+               if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
+                                       acpi_gbl_db_scope_buf)) {
+                       status = AE_BUFFER_OVERFLOW;
+                       goto error_exit;
+               }
+       }
+
+       if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
+                               info->name)) {
+               status = AE_BUFFER_OVERFLOW;
+               goto error_exit;
+       }
+
+       acpi_db_prep_namestring(info->pathname);
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+       acpi_os_printf("Evaluating %s\n", info->pathname);
+
+       if (info->flags & EX_SINGLE_STEP) {
+               acpi_gbl_cm_single_step = TRUE;
+               acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+       }
+
+       else {
+               /* No single step, allow redirection to a file */
+
+               acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+       }
+
+       return (AE_OK);
+
+error_exit:
+
+       ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
+       return (status);
+}
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
+{
+
+       return (cache->total_allocated - cache->total_freed -
+               cache->current_depth);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_outstanding_allocations
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Current global allocation count minus cache entries
+ *
+ * DESCRIPTION: Determine the current number of "outstanding" allocations --
+ *              those allocations that have not been freed and also are not
+ *              in one of the various object caches.
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_get_outstanding_allocations(void)
+{
+       u32 outstanding = 0;
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+
+       outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
+       outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
+       outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
+       outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
+#endif
+
+       return (outstanding);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execution_walk
+ *
+ * PARAMETERS:  WALK_CALLBACK
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a control method. Name is relative to the current
+ *              scope.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_execution_walk(acpi_handle obj_handle,
+                      u32 nesting_level, void *context, void **return_value)
+{
+       union acpi_operand_object *obj_desc;
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+       struct acpi_buffer return_obj;
+       acpi_status status;
+
+       obj_desc = acpi_ns_get_attached_object(node);
+       if (obj_desc->method.param_count) {
+               return (AE_OK);
+       }
+
+       return_obj.pointer = NULL;
+       return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+       acpi_ns_print_node_pathname(node, "Evaluating");
+
+       /* Do the actual method execution */
+
+       acpi_os_printf("\n");
+       acpi_gbl_method_executing = TRUE;
+
+       status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
+
+       acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
+                      acpi_ut_get_node_name(node),
+                      acpi_format_exception(status));
+
+       acpi_gbl_method_executing = FALSE;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute
+ *
+ * PARAMETERS:  name                - Name of method to execute
+ *              args                - Parameters to the method
+ *              Types               -
+ *              flags               - single step/no single step
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute a control method. Name is relative to the current
+ *              scope.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags)
+{
+       acpi_status status;
+       struct acpi_buffer return_obj;
+       char *name_string;
+
+#ifdef ACPI_DEBUG_OUTPUT
+       u32 previous_allocations;
+       u32 allocations;
+#endif
+
+       /*
+        * Allow one execution to be performed by debugger or single step
+        * execution will be dead locked by the interpreter mutexes.
+        */
+       if (acpi_gbl_method_executing) {
+               acpi_os_printf("Only one debugger execution is allowed.\n");
+               return;
+       }
+#ifdef ACPI_DEBUG_OUTPUT
+       /* Memory allocation tracking */
+
+       previous_allocations = acpi_db_get_outstanding_allocations();
+#endif
+
+       if (*name == '*') {
+               (void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
+                                         ACPI_UINT32_MAX,
+                                         acpi_db_execution_walk, NULL, NULL,
+                                         NULL);
+               return;
+       } else {
+               name_string = ACPI_ALLOCATE(strlen(name) + 1);
+               if (!name_string) {
+                       return;
+               }
+
+               memset(&acpi_gbl_db_method_info, 0,
+                      sizeof(struct acpi_db_method_info));
+
+               strcpy(name_string, name);
+               acpi_ut_strupr(name_string);
+               acpi_gbl_db_method_info.name = name_string;
+               acpi_gbl_db_method_info.args = args;
+               acpi_gbl_db_method_info.types = types;
+               acpi_gbl_db_method_info.flags = flags;
+
+               return_obj.pointer = NULL;
+               return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+               status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_FREE(name_string);
+                       return;
+               }
+
+               /* Get the NS node, determines existence also */
+
+               status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
+                                        &acpi_gbl_db_method_info.method);
+               if (ACPI_SUCCESS(status)) {
+                       status =
+                           acpi_db_execute_method(&acpi_gbl_db_method_info,
+                                                  &return_obj);
+               }
+               ACPI_FREE(name_string);
+       }
+
+       /*
+        * Allow any handlers in separate threads to complete.
+        * (Such as Notify handlers invoked from AML executed above).
+        */
+       acpi_os_sleep((u64)10);
+
+#ifdef ACPI_DEBUG_OUTPUT
+
+       /* Memory allocation tracking */
+
+       allocations =
+           acpi_db_get_outstanding_allocations() - previous_allocations;
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+
+       if (allocations > 0) {
+               acpi_os_printf
+                   ("0x%X Outstanding allocations after evaluation of %s\n",
+                    allocations, acpi_gbl_db_method_info.pathname);
+       }
+#endif
+
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Evaluation of %s failed with status %s\n",
+                              acpi_gbl_db_method_info.pathname,
+                              acpi_format_exception(status));
+       } else {
+               /* Display a return object, if any */
+
+               if (return_obj.length) {
+                       acpi_os_printf("Evaluation of %s returned object %p, "
+                                      "external buffer length %X\n",
+                                      acpi_gbl_db_method_info.pathname,
+                                      return_obj.pointer,
+                                      (u32)return_obj.length);
+
+                       acpi_db_dump_external_object(return_obj.pointer, 1);
+
+                       /* Dump a _PLD buffer if present */
+
+                       if (ACPI_COMPARE_NAME
+                           ((ACPI_CAST_PTR
+                             (struct acpi_namespace_node,
+                              acpi_gbl_db_method_info.method)->name.ascii),
+                            METHOD_NAME__PLD)) {
+                               acpi_db_dump_pld_buffer(return_obj.pointer);
+                       }
+               } else {
+                       acpi_os_printf
+                           ("No object was returned from evaluation of %s\n",
+                            acpi_gbl_db_method_info.pathname);
+               }
+       }
+
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_method_thread
+ *
+ * PARAMETERS:  context             - Execution info segment
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
+{
+       acpi_status status;
+       struct acpi_db_method_info *info = context;
+       struct acpi_db_method_info local_info;
+       u32 i;
+       u8 allow;
+       struct acpi_buffer return_obj;
+
+       /*
+        * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
+        * Prevent acpi_gbl_db_method_info from being modified by multiple threads
+        * concurrently.
+        *
+        * Note: The arguments we are passing are used by the ASL test suite
+        * (aslts). Do not change them without updating the tests.
+        */
+       (void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
+
+       if (info->init_args) {
+               acpi_db_uint32_to_hex_string(info->num_created,
+                                            info->index_of_thread_str);
+               acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
+                                            info->id_of_thread_str);
+       }
+
+       if (info->threads && (info->num_created < info->num_threads)) {
+               info->threads[info->num_created++] = acpi_os_get_thread_id();
+       }
+
+       local_info = *info;
+       local_info.args = local_info.arguments;
+       local_info.arguments[0] = local_info.num_threads_str;
+       local_info.arguments[1] = local_info.id_of_thread_str;
+       local_info.arguments[2] = local_info.index_of_thread_str;
+       local_info.arguments[3] = NULL;
+
+       local_info.types = local_info.arg_types;
+
+       (void)acpi_os_signal_semaphore(info->info_gate, 1);
+
+       for (i = 0; i < info->num_loops; i++) {
+               status = acpi_db_execute_method(&local_info, &return_obj);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf
+                           ("%s During evaluation of %s at iteration %X\n",
+                            acpi_format_exception(status), info->pathname, i);
+                       if (status == AE_ABORT_METHOD) {
+                               break;
+                       }
+               }
+#if 0
+               if ((i % 100) == 0) {
+                       acpi_os_printf("%u loops, Thread 0x%x\n",
+                                      i, acpi_os_get_thread_id());
+               }
+
+               if (return_obj.length) {
+                       acpi_os_printf
+                           ("Evaluation of %s returned object %p Buflen %X\n",
+                            info->pathname, return_obj.pointer,
+                            (u32)return_obj.length);
+                       acpi_db_dump_external_object(return_obj.pointer, 1);
+               }
+#endif
+       }
+
+       /* Signal our completion */
+
+       allow = 0;
+       (void)acpi_os_wait_semaphore(info->thread_complete_gate,
+                                    1, ACPI_WAIT_FOREVER);
+       info->num_completed++;
+
+       if (info->num_completed == info->num_threads) {
+
+               /* Do signal for main thread once only */
+               allow = 1;
+       }
+
+       (void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
+
+       if (allow) {
+               status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf
+                           ("Could not signal debugger thread sync semaphore, %s\n",
+                            acpi_format_exception(status));
+               }
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_create_execution_threads
+ *
+ * PARAMETERS:  num_threads_arg         - Number of threads to create
+ *              num_loops_arg           - Loop count for the thread(s)
+ *              method_name_arg         - Control method to execute
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Create threads to execute method(s)
+ *
+ ******************************************************************************/
+
+void
+acpi_db_create_execution_threads(char *num_threads_arg,
+                                char *num_loops_arg, char *method_name_arg)
+{
+       acpi_status status;
+       u32 num_threads;
+       u32 num_loops;
+       u32 i;
+       u32 size;
+       acpi_mutex main_thread_gate;
+       acpi_mutex thread_complete_gate;
+       acpi_mutex info_gate;
+
+       /* Get the arguments */
+
+       num_threads = strtoul(num_threads_arg, NULL, 0);
+       num_loops = strtoul(num_loops_arg, NULL, 0);
+
+       if (!num_threads || !num_loops) {
+               acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
+                              num_threads, num_loops);
+               return;
+       }
+
+       /*
+        * Create the semaphore for synchronization of
+        * the created threads with the main thread.
+        */
+       status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not create semaphore for "
+                              "synchronization with the main thread, %s\n",
+                              acpi_format_exception(status));
+               return;
+       }
+
+       /*
+        * Create the semaphore for synchronization
+        * between the created threads.
+        */
+       status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not create semaphore for "
+                              "synchronization between the created threads, %s\n",
+                              acpi_format_exception(status));
+
+               (void)acpi_os_delete_semaphore(main_thread_gate);
+               return;
+       }
+
+       status = acpi_os_create_semaphore(1, 1, &info_gate);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not create semaphore for "
+                              "synchronization of AcpiGbl_DbMethodInfo, %s\n",
+                              acpi_format_exception(status));
+
+               (void)acpi_os_delete_semaphore(thread_complete_gate);
+               (void)acpi_os_delete_semaphore(main_thread_gate);
+               return;
+       }
+
+       memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
+
+       /* Array to store IDs of threads */
+
+       acpi_gbl_db_method_info.num_threads = num_threads;
+       size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
+
+       acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
+       if (acpi_gbl_db_method_info.threads == NULL) {
+               acpi_os_printf("No memory for thread IDs array\n");
+               (void)acpi_os_delete_semaphore(main_thread_gate);
+               (void)acpi_os_delete_semaphore(thread_complete_gate);
+               (void)acpi_os_delete_semaphore(info_gate);
+               return;
+       }
+       memset(acpi_gbl_db_method_info.threads, 0, size);
+
+       /* Setup the context to be passed to each thread */
+
+       acpi_gbl_db_method_info.name = method_name_arg;
+       acpi_gbl_db_method_info.flags = 0;
+       acpi_gbl_db_method_info.num_loops = num_loops;
+       acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
+       acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
+       acpi_gbl_db_method_info.info_gate = info_gate;
+
+       /* Init arguments to be passed to method */
+
+       acpi_gbl_db_method_info.init_args = 1;
+       acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
+       acpi_gbl_db_method_info.arguments[0] =
+           acpi_gbl_db_method_info.num_threads_str;
+       acpi_gbl_db_method_info.arguments[1] =
+           acpi_gbl_db_method_info.id_of_thread_str;
+       acpi_gbl_db_method_info.arguments[2] =
+           acpi_gbl_db_method_info.index_of_thread_str;
+       acpi_gbl_db_method_info.arguments[3] = NULL;
+
+       acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
+       acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
+       acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
+       acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
+
+       acpi_db_uint32_to_hex_string(num_threads,
+                                    acpi_gbl_db_method_info.num_threads_str);
+
+       status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
+       if (ACPI_FAILURE(status)) {
+               goto cleanup_and_exit;
+       }
+
+       /* Get the NS node, determines existence also */
+
+       status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
+                                &acpi_gbl_db_method_info.method);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("%s Could not get handle for %s\n",
+                              acpi_format_exception(status),
+                              acpi_gbl_db_method_info.pathname);
+               goto cleanup_and_exit;
+       }
+
+       /* Create the threads */
+
+       acpi_os_printf("Creating %X threads to execute %X times each\n",
+                      num_threads, num_loops);
+
+       for (i = 0; i < (num_threads); i++) {
+               status =
+                   acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
+                                   acpi_db_method_thread,
+                                   &acpi_gbl_db_method_info);
+               if (ACPI_FAILURE(status)) {
+                       break;
+               }
+       }
+
+       /* Wait for all threads to complete */
+
+       (void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+       acpi_os_printf("All threads (%X) have completed\n", num_threads);
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+
+cleanup_and_exit:
+
+       /* Cleanup and exit */
+
+       (void)acpi_os_delete_semaphore(main_thread_gate);
+       (void)acpi_os_delete_semaphore(thread_complete_gate);
+       (void)acpi_os_delete_semaphore(info_gate);
+
+       acpi_os_free(acpi_gbl_db_method_info.threads);
+       acpi_gbl_db_method_info.threads = NULL;
+}
diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c
new file mode 100644 (file)
index 0000000..d0e6b20
--- /dev/null
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ *
+ * Module Name: dbfileio - Debugger file I/O commands. These can't usually
+ *              be used when running the debugger in Ring 0 (Kernel mode)
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbfileio")
+
+#ifdef ACPI_DEBUGGER
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_close_debug_file
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: If open, close the current debug output file
+ *
+ ******************************************************************************/
+void acpi_db_close_debug_file(void)
+{
+
+#ifdef ACPI_APPLICATION
+
+       if (acpi_gbl_debug_file) {
+               fclose(acpi_gbl_debug_file);
+               acpi_gbl_debug_file = NULL;
+               acpi_gbl_db_output_to_file = FALSE;
+               acpi_os_printf("Debug output file %s closed\n",
+                              acpi_gbl_db_debug_filename);
+       }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_open_debug_file
+ *
+ * PARAMETERS:  name                - Filename to open
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Open a file where debug output will be directed.
+ *
+ ******************************************************************************/
+
+void acpi_db_open_debug_file(char *name)
+{
+
+#ifdef ACPI_APPLICATION
+
+       acpi_db_close_debug_file();
+       acpi_gbl_debug_file = fopen(name, "w+");
+       if (!acpi_gbl_debug_file) {
+               acpi_os_printf("Could not open debug file %s\n", name);
+               return;
+       }
+
+       acpi_os_printf("Debug output file %s opened\n", name);
+       strncpy(acpi_gbl_db_debug_filename, name,
+               sizeof(acpi_gbl_db_debug_filename));
+       acpi_gbl_db_output_to_file = TRUE;
+
+#endif
+}
+#endif
+
+#ifdef ACPI_APPLICATION
+#include "acapps.h"
+
+/*******************************************************************************
+ *
+ * FUNCTION:    ae_local_load_table
+ *
+ * PARAMETERS:  table           - pointer to a buffer containing the entire
+ *                                table to be loaded
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to load a table from the caller's
+ *              buffer. The buffer must contain an entire ACPI Table including
+ *              a valid header. The header fields will be verified, and if it
+ *              is determined that the table is invalid, the call will fail.
+ *
+ ******************************************************************************/
+
+static acpi_status ae_local_load_table(struct acpi_table_header *table)
+{
+       acpi_status status = AE_OK;
+
+       ACPI_FUNCTION_TRACE(ae_local_load_table);
+
+#if 0
+/*    struct acpi_table_desc          table_info; */
+
+       if (!table) {
+               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       }
+
+       table_info.pointer = table;
+       status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       /* Install the new table into the local data structures */
+
+       status = acpi_tb_init_table_descriptor(&table_info);
+       if (ACPI_FAILURE(status)) {
+               if (status == AE_ALREADY_EXISTS) {
+
+                       /* Table already exists, no error */
+
+                       status = AE_OK;
+               }
+
+               /* Free table allocated by acpi_tb_get_table */
+
+               acpi_tb_delete_single_table(&table_info);
+               return_ACPI_STATUS(status);
+       }
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
+       status =
+           acpi_ns_load_table(table_info.installed_desc, acpi_gbl_root_node);
+       if (ACPI_FAILURE(status)) {
+
+               /* Uninstall table and free the buffer */
+
+               acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_DSDT);
+               return_ACPI_STATUS(status);
+       }
+#endif
+#endif
+
+       return_ACPI_STATUS(status);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_table_from_file
+ *
+ * PARAMETERS:  filename        - File where table is located
+ *              return_table    - Where a pointer to the table is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load an ACPI table from a file
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_get_table_from_file(char *filename,
+                           struct acpi_table_header **return_table,
+                           u8 must_be_aml_file)
+{
+#ifdef ACPI_APPLICATION
+       acpi_status status;
+       struct acpi_table_header *table;
+       u8 is_aml_table = TRUE;
+
+       status = acpi_ut_read_table_from_file(filename, &table);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       if (must_be_aml_file) {
+               is_aml_table = acpi_ut_is_aml_table(table);
+               if (!is_aml_table) {
+                       ACPI_EXCEPTION((AE_INFO, AE_OK,
+                                       "Input for -e is not an AML table: "
+                                       "\"%4.4s\" (must be DSDT/SSDT)",
+                                       table->signature));
+                       return (AE_TYPE);
+               }
+       }
+
+       if (is_aml_table) {
+
+               /* Attempt to recognize and install the table */
+
+               status = ae_local_load_table(table);
+               if (ACPI_FAILURE(status)) {
+                       if (status == AE_ALREADY_EXISTS) {
+                               acpi_os_printf
+                                   ("Table %4.4s is already installed\n",
+                                    table->signature);
+                       } else {
+                               acpi_os_printf("Could not install table, %s\n",
+                                              acpi_format_exception(status));
+                       }
+
+                       return (status);
+               }
+
+               acpi_tb_print_table_header(0, table);
+
+               fprintf(stderr,
+                       "Acpi table [%4.4s] successfully installed and loaded\n",
+                       table->signature);
+       }
+
+       acpi_gbl_acpi_hardware_present = FALSE;
+       if (return_table) {
+               *return_table = table;
+       }
+
+#endif                         /* ACPI_APPLICATION */
+       return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c
new file mode 100644 (file)
index 0000000..9c66a9e
--- /dev/null
@@ -0,0 +1,239 @@
+/******************************************************************************
+ *
+ * Module Name: dbhistry - debugger HISTORY command
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbhistry")
+
+#define HI_NO_HISTORY       0
+#define HI_RECORD_HISTORY   1
+#define HISTORY_SIZE        40
+typedef struct history_info {
+       char *command;
+       u32 cmd_num;
+
+} HISTORY_INFO;
+
+static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE];
+static u16 acpi_gbl_lo_history = 0;
+static u16 acpi_gbl_num_history = 0;
+static u16 acpi_gbl_next_history_index = 0;
+u32 acpi_gbl_next_cmd_num = 1;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_add_to_history
+ *
+ * PARAMETERS:  command_line    - Command to add
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Add a command line to the history buffer.
+ *
+ ******************************************************************************/
+
+void acpi_db_add_to_history(char *command_line)
+{
+       u16 cmd_len;
+       u16 buffer_len;
+
+       /* Put command into the next available slot */
+
+       cmd_len = (u16)strlen(command_line);
+       if (!cmd_len) {
+               return;
+       }
+
+       if (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command !=
+           NULL) {
+               buffer_len =
+                   (u16)
+                   strlen(acpi_gbl_history_buffer[acpi_gbl_next_history_index].
+                          command);
+
+               if (cmd_len > buffer_len) {
+                       acpi_os_free(acpi_gbl_history_buffer
+                                    [acpi_gbl_next_history_index].command);
+                       acpi_gbl_history_buffer[acpi_gbl_next_history_index].
+                           command = acpi_os_allocate(cmd_len + 1);
+               }
+       } else {
+               acpi_gbl_history_buffer[acpi_gbl_next_history_index].command =
+                   acpi_os_allocate(cmd_len + 1);
+       }
+
+       strcpy(acpi_gbl_history_buffer[acpi_gbl_next_history_index].command,
+              command_line);
+
+       acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num =
+           acpi_gbl_next_cmd_num;
+
+       /* Adjust indexes */
+
+       if ((acpi_gbl_num_history == HISTORY_SIZE) &&
+           (acpi_gbl_next_history_index == acpi_gbl_lo_history)) {
+               acpi_gbl_lo_history++;
+               if (acpi_gbl_lo_history >= HISTORY_SIZE) {
+                       acpi_gbl_lo_history = 0;
+               }
+       }
+
+       acpi_gbl_next_history_index++;
+       if (acpi_gbl_next_history_index >= HISTORY_SIZE) {
+               acpi_gbl_next_history_index = 0;
+       }
+
+       acpi_gbl_next_cmd_num++;
+       if (acpi_gbl_num_history < HISTORY_SIZE) {
+               acpi_gbl_num_history++;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_history
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the contents of the history buffer
+ *
+ ******************************************************************************/
+
+void acpi_db_display_history(void)
+{
+       u32 i;
+       u16 history_index;
+
+       history_index = acpi_gbl_lo_history;
+
+       /* Dump entire history buffer */
+
+       for (i = 0; i < acpi_gbl_num_history; i++) {
+               if (acpi_gbl_history_buffer[history_index].command) {
+                       acpi_os_printf("%3ld %s\n",
+                                      acpi_gbl_history_buffer[history_index].
+                                      cmd_num,
+                                      acpi_gbl_history_buffer[history_index].
+                                      command);
+               }
+
+               history_index++;
+               if (history_index >= HISTORY_SIZE) {
+                       history_index = 0;
+               }
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_from_history
+ *
+ * PARAMETERS:  command_num_arg         - String containing the number of the
+ *                                        command to be retrieved
+ *
+ * RETURN:      Pointer to the retrieved command. Null on error.
+ *
+ * DESCRIPTION: Get a command from the history buffer
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_from_history(char *command_num_arg)
+{
+       u32 cmd_num;
+
+       if (command_num_arg == NULL) {
+               cmd_num = acpi_gbl_next_cmd_num - 1;
+       }
+
+       else {
+               cmd_num = strtoul(command_num_arg, NULL, 0);
+       }
+
+       return (acpi_db_get_history_by_index(cmd_num));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_history_by_index
+ *
+ * PARAMETERS:  cmd_num             - Index of the desired history entry.
+ *                                    Values are 0...(acpi_gbl_next_cmd_num - 1)
+ *
+ * RETURN:      Pointer to the retrieved command. Null on error.
+ *
+ * DESCRIPTION: Get a command from the history buffer
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_history_by_index(u32 cmd_num)
+{
+       u32 i;
+       u16 history_index;
+
+       /* Search history buffer */
+
+       history_index = acpi_gbl_lo_history;
+       for (i = 0; i < acpi_gbl_num_history; i++) {
+               if (acpi_gbl_history_buffer[history_index].cmd_num == cmd_num) {
+
+                       /* Found the command, return it */
+
+                       return (acpi_gbl_history_buffer[history_index].command);
+               }
+
+               /* History buffer is circular */
+
+               history_index++;
+               if (history_index >= HISTORY_SIZE) {
+                       history_index = 0;
+               }
+       }
+
+       acpi_os_printf("Invalid history number: %u\n", history_index);
+       return (NULL);
+}
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
new file mode 100644 (file)
index 0000000..0480254
--- /dev/null
@@ -0,0 +1,1267 @@
+/*******************************************************************************
+ *
+ * Module Name: dbinput - user front-end to the AML debugger
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbinput")
+
+/* Local prototypes */
+static u32 acpi_db_get_line(char *input_buffer);
+
+static u32 acpi_db_match_command(char *user_command);
+
+static void acpi_db_single_thread(void);
+
+static void acpi_db_display_command_info(char *command, u8 display_all);
+
+static void acpi_db_display_help(char *command);
+
+static u8
+acpi_db_match_command_help(char *command,
+                          const struct acpi_db_command_help *help);
+
+/*
+ * Top-level debugger commands.
+ *
+ * This list of commands must match the string table below it
+ */
+enum acpi_ex_debugger_commands {
+       CMD_NOT_FOUND = 0,
+       CMD_NULL,
+       CMD_ALLOCATIONS,
+       CMD_ARGS,
+       CMD_ARGUMENTS,
+       CMD_BREAKPOINT,
+       CMD_BUSINFO,
+       CMD_CALL,
+       CMD_DEBUG,
+       CMD_DISASSEMBLE,
+       CMD_DISASM,
+       CMD_DUMP,
+       CMD_EVALUATE,
+       CMD_EXECUTE,
+       CMD_EXIT,
+       CMD_FIND,
+       CMD_GO,
+       CMD_HANDLERS,
+       CMD_HELP,
+       CMD_HELP2,
+       CMD_HISTORY,
+       CMD_HISTORY_EXE,
+       CMD_HISTORY_LAST,
+       CMD_INFORMATION,
+       CMD_INTEGRITY,
+       CMD_INTO,
+       CMD_LEVEL,
+       CMD_LIST,
+       CMD_LOCALS,
+       CMD_LOCKS,
+       CMD_METHODS,
+       CMD_NAMESPACE,
+       CMD_NOTIFY,
+       CMD_OBJECTS,
+       CMD_OSI,
+       CMD_OWNER,
+       CMD_PATHS,
+       CMD_PREDEFINED,
+       CMD_PREFIX,
+       CMD_QUIT,
+       CMD_REFERENCES,
+       CMD_RESOURCES,
+       CMD_RESULTS,
+       CMD_SET,
+       CMD_STATS,
+       CMD_STOP,
+       CMD_TABLES,
+       CMD_TEMPLATE,
+       CMD_TRACE,
+       CMD_TREE,
+       CMD_TYPE,
+#ifdef ACPI_APPLICATION
+       CMD_ENABLEACPI,
+       CMD_EVENT,
+       CMD_GPE,
+       CMD_GPES,
+       CMD_SCI,
+       CMD_SLEEP,
+
+       CMD_CLOSE,
+       CMD_LOAD,
+       CMD_OPEN,
+       CMD_UNLOAD,
+
+       CMD_TERMINATE,
+       CMD_THREADS,
+
+       CMD_TEST,
+#endif
+};
+
+#define CMD_FIRST_VALID     2
+
+/* Second parameter is the required argument count */
+
+static const struct acpi_db_command_info acpi_gbl_db_commands[] = {
+       {"<NOT FOUND>", 0},
+       {"<NULL>", 0},
+       {"ALLOCATIONS", 0},
+       {"ARGS", 0},
+       {"ARGUMENTS", 0},
+       {"BREAKPOINT", 1},
+       {"BUSINFO", 0},
+       {"CALL", 0},
+       {"DEBUG", 1},
+       {"DISASSEMBLE", 1},
+       {"DISASM", 1},
+       {"DUMP", 1},
+       {"EVALUATE", 1},
+       {"EXECUTE", 1},
+       {"EXIT", 0},
+       {"FIND", 1},
+       {"GO", 0},
+       {"HANDLERS", 0},
+       {"HELP", 0},
+       {"?", 0},
+       {"HISTORY", 0},
+       {"!", 1},
+       {"!!", 0},
+       {"INFORMATION", 0},
+       {"INTEGRITY", 0},
+       {"INTO", 0},
+       {"LEVEL", 0},
+       {"LIST", 0},
+       {"LOCALS", 0},
+       {"LOCKS", 0},
+       {"METHODS", 0},
+       {"NAMESPACE", 0},
+       {"NOTIFY", 2},
+       {"OBJECTS", 0},
+       {"OSI", 0},
+       {"OWNER", 1},
+       {"PATHS", 0},
+       {"PREDEFINED", 0},
+       {"PREFIX", 0},
+       {"QUIT", 0},
+       {"REFERENCES", 1},
+       {"RESOURCES", 0},
+       {"RESULTS", 0},
+       {"SET", 3},
+       {"STATS", 1},
+       {"STOP", 0},
+       {"TABLES", 0},
+       {"TEMPLATE", 1},
+       {"TRACE", 1},
+       {"TREE", 0},
+       {"TYPE", 1},
+#ifdef ACPI_APPLICATION
+       {"ENABLEACPI", 0},
+       {"EVENT", 1},
+       {"GPE", 1},
+       {"GPES", 0},
+       {"SCI", 0},
+       {"SLEEP", 0},
+
+       {"CLOSE", 0},
+       {"LOAD", 1},
+       {"OPEN", 1},
+       {"UNLOAD", 1},
+
+       {"TERMINATE", 0},
+       {"THREADS", 3},
+
+       {"TEST", 1},
+#endif
+       {NULL, 0}
+};
+
+/*
+ * Help for all debugger commands. First argument is the number of lines
+ * of help to output for the command.
+ */
+static const struct acpi_db_command_help acpi_gbl_db_command_help[] = {
+       {0, "\nGeneral-Purpose Commands:", "\n"},
+       {1, "  Allocations", "Display list of current memory allocations\n"},
+       {2, "  Dump <Address>|<Namepath>", "\n"},
+       {0, "       [Byte|Word|Dword|Qword]",
+        "Display ACPI objects or memory\n"},
+       {1, "  Handlers", "Info about global handlers\n"},
+       {1, "  Help [Command]", "This help screen or individual command\n"},
+       {1, "  History", "Display command history buffer\n"},
+       {1, "  Level <DebugLevel>] [console]",
+        "Get/Set debug level for file or console\n"},
+       {1, "  Locks", "Current status of internal mutexes\n"},
+       {1, "  Osi [Install|Remove <name>]",
+        "Display or modify global _OSI list\n"},
+       {1, "  Quit or Exit", "Exit this command\n"},
+       {8, "  Stats <SubCommand>",
+        "Display namespace and memory statistics\n"},
+       {1, "     Allocations", "Display list of current memory allocations\n"},
+       {1, "     Memory", "Dump internal memory lists\n"},
+       {1, "     Misc", "Namespace search and mutex stats\n"},
+       {1, "     Objects", "Summary of namespace objects\n"},
+       {1, "     Sizes", "Sizes for each of the internal objects\n"},
+       {1, "     Stack", "Display CPU stack usage\n"},
+       {1, "     Tables", "Info about current ACPI table(s)\n"},
+       {1, "  Tables", "Display info about loaded ACPI tables\n"},
+       {1, "  ! <CommandNumber>", "Execute command from history buffer\n"},
+       {1, "  !!", "Execute last command again\n"},
+
+       {0, "\nNamespace Access Commands:", "\n"},
+       {1, "  Businfo", "Display system bus info\n"},
+       {1, "  Disassemble <Method>", "Disassemble a control method\n"},
+       {1, "  Find <AcpiName> (? is wildcard)",
+        "Find ACPI name(s) with wildcards\n"},
+       {1, "  Integrity", "Validate namespace integrity\n"},
+       {1, "  Methods", "Display list of loaded control methods\n"},
+       {1, "  Namespace [Object] [Depth]",
+        "Display loaded namespace tree/subtree\n"},
+       {1, "  Notify <Object> <Value>", "Send a notification on Object\n"},
+       {1, "  Objects [ObjectType]",
+        "Display summary of all objects or just given type\n"},
+       {1, "  Owner <OwnerId> [Depth]",
+        "Display loaded namespace by object owner\n"},
+       {1, "  Paths", "Display full pathnames of namespace objects\n"},
+       {1, "  Predefined", "Check all predefined names\n"},
+       {1, "  Prefix [<Namepath>]", "Set or Get current execution prefix\n"},
+       {1, "  References <Addr>", "Find all references to object at addr\n"},
+       {1, "  Resources [DeviceName]",
+        "Display Device resources (no arg = all devices)\n"},
+       {1, "  Set N <NamedObject> <Value>", "Set value for named integer\n"},
+       {1, "  Template <Object>", "Format/dump a Buffer/ResourceTemplate\n"},
+       {1, "  Type <Object>", "Display object type\n"},
+
+       {0, "\nControl Method Execution Commands:", "\n"},
+       {1, "  Arguments (or Args)", "Display method arguments\n"},
+       {1, "  Breakpoint <AmlOffset>", "Set an AML execution breakpoint\n"},
+       {1, "  Call", "Run to next control method invocation\n"},
+       {1, "  Debug <Namepath> [Arguments]", "Single Step a control method\n"},
+       {6, "  Evaluate", "Synonym for Execute\n"},
+       {5, "  Execute <Namepath> [Arguments]", "Execute control method\n"},
+       {1, "     Hex Integer", "Integer method argument\n"},
+       {1, "     \"Ascii String\"", "String method argument\n"},
+       {1, "     (Hex Byte List)", "Buffer method argument\n"},
+       {1, "     [Package Element List]", "Package method argument\n"},
+       {1, "  Go", "Allow method to run to completion\n"},
+       {1, "  Information", "Display info about the current method\n"},
+       {1, "  Into", "Step into (not over) a method call\n"},
+       {1, "  List [# of Aml Opcodes]", "Display method ASL statements\n"},
+       {1, "  Locals", "Display method local variables\n"},
+       {1, "  Results", "Display method result stack\n"},
+       {1, "  Set <A|L> <#> <Value>", "Set method data (Arguments/Locals)\n"},
+       {1, "  Stop", "Terminate control method\n"},
+       {5, "  Trace <State> [<Namepath>] [Once]",
+        "Trace control method execution\n"},
+       {1, "     Enable", "Enable all messages\n"},
+       {1, "     Disable", "Disable tracing\n"},
+       {1, "     Method", "Enable method execution messages\n"},
+       {1, "     Opcode", "Enable opcode execution messages\n"},
+       {1, "  Tree", "Display control method calling tree\n"},
+       {1, "  <Enter>", "Single step next AML opcode (over calls)\n"},
+
+#ifdef ACPI_APPLICATION
+       {0, "\nHardware Simulation Commands:", "\n"},
+       {1, "  EnableAcpi", "Enable ACPI (hardware) mode\n"},
+       {1, "  Event <F|G> <Value>", "Generate AcpiEvent (Fixed/GPE)\n"},
+       {1, "  Gpe <GpeNum> [GpeBlockDevice]", "Simulate a GPE\n"},
+       {1, "  Gpes", "Display info on all GPE devices\n"},
+       {1, "  Sci", "Generate an SCI\n"},
+       {1, "  Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"},
+
+       {0, "\nFile I/O Commands:", "\n"},
+       {1, "  Close", "Close debug output file\n"},
+       {1, "  Load <Input Filename>", "Load ACPI table from a file\n"},
+       {1, "  Open <Output Filename>", "Open a file for debug output\n"},
+       {1, "  Unload <Namepath>",
+        "Unload an ACPI table via namespace object\n"},
+
+       {0, "\nUser Space Commands:", "\n"},
+       {1, "  Terminate", "Delete namespace and all internal objects\n"},
+       {1, "  Thread <Threads><Loops><NamePath>",
+        "Spawn threads to execute method(s)\n"},
+
+       {0, "\nDebug Test Commands:", "\n"},
+       {3, "  Test <TestName>", "Invoke a debug test\n"},
+       {1, "     Objects", "Read/write/compare all namespace data objects\n"},
+       {1, "     Predefined",
+        "Execute all ACPI predefined names (_STA, etc.)\n"},
+#endif
+       {0, NULL, NULL}
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_command_help
+ *
+ * PARAMETERS:  command             - Command string to match
+ *              help                - Help table entry to attempt match
+ *
+ * RETURN:      TRUE if command matched, FALSE otherwise
+ *
+ * DESCRIPTION: Attempt to match a command in the help table in order to
+ *              print help information for a single command.
+ *
+ ******************************************************************************/
+
+static u8
+acpi_db_match_command_help(char *command,
+                          const struct acpi_db_command_help *help)
+{
+       char *invocation = help->invocation;
+       u32 line_count;
+
+       /* Valid commands in the help table begin with a couple of spaces */
+
+       if (*invocation != ' ') {
+               return (FALSE);
+       }
+
+       while (*invocation == ' ') {
+               invocation++;
+       }
+
+       /* Match command name (full command or substring) */
+
+       while ((*command) && (*invocation) && (*invocation != ' ')) {
+               if (tolower((int)*command) != tolower((int)*invocation)) {
+                       return (FALSE);
+               }
+
+               invocation++;
+               command++;
+       }
+
+       /* Print the appropriate number of help lines */
+
+       line_count = help->line_count;
+       while (line_count) {
+               acpi_os_printf("%-38s : %s", help->invocation,
+                              help->description);
+               help++;
+               line_count--;
+       }
+
+       return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_command_info
+ *
+ * PARAMETERS:  command             - Command string to match
+ *              display_all         - Display all matching commands, or just
+ *                                    the first one (substring match)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display help information for a Debugger command.
+ *
+ ******************************************************************************/
+
+static void acpi_db_display_command_info(char *command, u8 display_all)
+{
+       const struct acpi_db_command_help *next;
+       u8 matched;
+
+       next = acpi_gbl_db_command_help;
+       while (next->invocation) {
+               matched = acpi_db_match_command_help(command, next);
+               if (!display_all && matched) {
+                       return;
+               }
+
+               next++;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_help
+ *
+ * PARAMETERS:  command             - Optional command string to display help.
+ *                                    if not specified, all debugger command
+ *                                    help strings are displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display help for a single debugger command, or all of them.
+ *
+ ******************************************************************************/
+
+static void acpi_db_display_help(char *command)
+{
+       const struct acpi_db_command_help *next = acpi_gbl_db_command_help;
+
+       if (!command) {
+
+               /* No argument to help, display help for all commands */
+
+               while (next->invocation) {
+                       acpi_os_printf("%-38s%s", next->invocation,
+                                      next->description);
+                       next++;
+               }
+       } else {
+               /* Display help for all commands that match the subtring */
+
+               acpi_db_display_command_info(command, TRUE);
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_next_token
+ *
+ * PARAMETERS:  string          - Command buffer
+ *              next            - Return value, end of next token
+ *
+ * RETURN:      Pointer to the start of the next token.
+ *
+ * DESCRIPTION: Command line parsing. Get the next token on the command line
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_next_token(char *string,
+                            char **next, acpi_object_type * return_type)
+{
+       char *start;
+       u32 depth;
+       acpi_object_type type = ACPI_TYPE_INTEGER;
+
+       /* At end of buffer? */
+
+       if (!string || !(*string)) {
+               return (NULL);
+       }
+
+       /* Remove any spaces at the beginning */
+
+       if (*string == ' ') {
+               while (*string && (*string == ' ')) {
+                       string++;
+               }
+
+               if (!(*string)) {
+                       return (NULL);
+               }
+       }
+
+       switch (*string) {
+       case '"':
+
+               /* This is a quoted string, scan until closing quote */
+
+               string++;
+               start = string;
+               type = ACPI_TYPE_STRING;
+
+               /* Find end of string */
+
+               while (*string && (*string != '"')) {
+                       string++;
+               }
+               break;
+
+       case '(':
+
+               /* This is the start of a buffer, scan until closing paren */
+
+               string++;
+               start = string;
+               type = ACPI_TYPE_BUFFER;
+
+               /* Find end of buffer */
+
+               while (*string && (*string != ')')) {
+                       string++;
+               }
+               break;
+
+       case '[':
+
+               /* This is the start of a package, scan until closing bracket */
+
+               string++;
+               depth = 1;
+               start = string;
+               type = ACPI_TYPE_PACKAGE;
+
+               /* Find end of package (closing bracket) */
+
+               while (*string) {
+
+                       /* Handle String package elements */
+
+                       if (*string == '"') {
+                               /* Find end of string */
+
+                               string++;
+                               while (*string && (*string != '"')) {
+                                       string++;
+                               }
+                               if (!(*string)) {
+                                       break;
+                               }
+                       } else if (*string == '[') {
+                               depth++;        /* A nested package declaration */
+                       } else if (*string == ']') {
+                               depth--;
+                               if (depth == 0) {       /* Found final package closing bracket */
+                                       break;
+                               }
+                       }
+
+                       string++;
+               }
+               break;
+
+       default:
+
+               start = string;
+
+               /* Find end of token */
+
+               while (*string && (*string != ' ')) {
+                       string++;
+               }
+               break;
+       }
+
+       if (!(*string)) {
+               *next = NULL;
+       } else {
+               *string = 0;
+               *next = string + 1;
+       }
+
+       *return_type = type;
+       return (start);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_line
+ *
+ * PARAMETERS:  input_buffer        - Command line buffer
+ *
+ * RETURN:      Count of arguments to the command
+ *
+ * DESCRIPTION: Get the next command line from the user. Gets entire line
+ *              up to the next newline
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_get_line(char *input_buffer)
+{
+       u32 i;
+       u32 count;
+       char *next;
+       char *this;
+
+       if (acpi_ut_safe_strcpy
+           (acpi_gbl_db_parsed_buf, sizeof(acpi_gbl_db_parsed_buf),
+            input_buffer)) {
+               acpi_os_printf
+                   ("Buffer overflow while parsing input line (max %u characters)\n",
+                    sizeof(acpi_gbl_db_parsed_buf));
+               return (0);
+       }
+
+       this = acpi_gbl_db_parsed_buf;
+       for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) {
+               acpi_gbl_db_args[i] = acpi_db_get_next_token(this, &next,
+                                                            &acpi_gbl_db_arg_types
+                                                            [i]);
+               if (!acpi_gbl_db_args[i]) {
+                       break;
+               }
+
+               this = next;
+       }
+
+       /* Uppercase the actual command */
+
+       if (acpi_gbl_db_args[0]) {
+               acpi_ut_strupr(acpi_gbl_db_args[0]);
+       }
+
+       count = i;
+       if (count) {
+               count--;        /* Number of args only */
+       }
+
+       return (count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_command
+ *
+ * PARAMETERS:  user_command            - User command line
+ *
+ * RETURN:      Index into command array, -1 if not found
+ *
+ * DESCRIPTION: Search command array for a command match
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_match_command(char *user_command)
+{
+       u32 i;
+
+       if (!user_command || user_command[0] == 0) {
+               return (CMD_NULL);
+       }
+
+       for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++) {
+               if (strstr(acpi_gbl_db_commands[i].name, user_command) ==
+                   acpi_gbl_db_commands[i].name) {
+                       return (i);
+               }
+       }
+
+       /* Command not recognized */
+
+       return (CMD_NOT_FOUND);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_command_dispatch
+ *
+ * PARAMETERS:  input_buffer        - Command line buffer
+ *              walk_state          - Current walk
+ *              op                  - Current (executing) parse op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Command dispatcher.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_command_dispatch(char *input_buffer,
+                        struct acpi_walk_state * walk_state,
+                        union acpi_parse_object * op)
+{
+       u32 temp;
+       u32 command_index;
+       u32 param_count;
+       char *command_line;
+       acpi_status status = AE_CTRL_TRUE;
+
+       /* If acpi_terminate has been called, terminate this thread */
+
+       if (acpi_gbl_db_terminate_loop) {
+               return (AE_CTRL_TERMINATE);
+       }
+
+       /* Find command and add to the history buffer */
+
+       param_count = acpi_db_get_line(input_buffer);
+       command_index = acpi_db_match_command(acpi_gbl_db_args[0]);
+       temp = 0;
+
+       /*
+        * We don't want to add the !! command to the history buffer. It
+        * would cause an infinite loop because it would always be the
+        * previous command.
+        */
+       if (command_index != CMD_HISTORY_LAST) {
+               acpi_db_add_to_history(input_buffer);
+       }
+
+       /* Verify that we have the minimum number of params */
+
+       if (param_count < acpi_gbl_db_commands[command_index].min_args) {
+               acpi_os_printf
+                   ("%u parameters entered, [%s] requires %u parameters\n",
+                    param_count, acpi_gbl_db_commands[command_index].name,
+                    acpi_gbl_db_commands[command_index].min_args);
+
+               acpi_db_display_command_info(acpi_gbl_db_commands
+                                            [command_index].name, FALSE);
+               return (AE_CTRL_TRUE);
+       }
+
+       /* Decode and dispatch the command */
+
+       switch (command_index) {
+       case CMD_NULL:
+
+               if (op) {
+                       return (AE_OK);
+               }
+               break;
+
+       case CMD_ALLOCATIONS:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+               acpi_ut_dump_allocations((u32)-1, NULL);
+#endif
+               break;
+
+       case CMD_ARGS:
+       case CMD_ARGUMENTS:
+
+               acpi_db_display_arguments();
+               break;
+
+       case CMD_BREAKPOINT:
+
+               acpi_db_set_method_breakpoint(acpi_gbl_db_args[1], walk_state,
+                                             op);
+               break;
+
+       case CMD_BUSINFO:
+
+               acpi_db_get_bus_info();
+               break;
+
+       case CMD_CALL:
+
+               acpi_db_set_method_call_breakpoint(op);
+               status = AE_OK;
+               break;
+
+       case CMD_DEBUG:
+
+               acpi_db_execute(acpi_gbl_db_args[1],
+                               &acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2],
+                               EX_SINGLE_STEP);
+               break;
+
+       case CMD_DISASSEMBLE:
+       case CMD_DISASM:
+
+               (void)acpi_db_disassemble_method(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_DUMP:
+
+               acpi_db_decode_and_display_object(acpi_gbl_db_args[1],
+                                                 acpi_gbl_db_args[2]);
+               break;
+
+       case CMD_EVALUATE:
+       case CMD_EXECUTE:
+
+               acpi_db_execute(acpi_gbl_db_args[1],
+                               &acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2],
+                               EX_NO_SINGLE_STEP);
+               break;
+
+       case CMD_FIND:
+
+               status = acpi_db_find_name_in_namespace(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_GO:
+
+               acpi_gbl_cm_single_step = FALSE;
+               return (AE_OK);
+
+       case CMD_HANDLERS:
+
+               acpi_db_display_handlers();
+               break;
+
+       case CMD_HELP:
+       case CMD_HELP2:
+
+               acpi_db_display_help(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_HISTORY:
+
+               acpi_db_display_history();
+               break;
+
+       case CMD_HISTORY_EXE:   /* ! command */
+
+               command_line = acpi_db_get_from_history(acpi_gbl_db_args[1]);
+               if (!command_line) {
+                       return (AE_CTRL_TRUE);
+               }
+
+               status = acpi_db_command_dispatch(command_line, walk_state, op);
+               return (status);
+
+       case CMD_HISTORY_LAST:  /* !! command */
+
+               command_line = acpi_db_get_from_history(NULL);
+               if (!command_line) {
+                       return (AE_CTRL_TRUE);
+               }
+
+               status = acpi_db_command_dispatch(command_line, walk_state, op);
+               return (status);
+
+       case CMD_INFORMATION:
+
+               acpi_db_display_method_info(op);
+               break;
+
+       case CMD_INTEGRITY:
+
+               acpi_db_check_integrity();
+               break;
+
+       case CMD_INTO:
+
+               if (op) {
+                       acpi_gbl_cm_single_step = TRUE;
+                       return (AE_OK);
+               }
+               break;
+
+       case CMD_LEVEL:
+
+               if (param_count == 0) {
+                       acpi_os_printf
+                           ("Current debug level for file output is:    %8.8lX\n",
+                            acpi_gbl_db_debug_level);
+                       acpi_os_printf
+                           ("Current debug level for console output is: %8.8lX\n",
+                            acpi_gbl_db_console_debug_level);
+               } else if (param_count == 2) {
+                       temp = acpi_gbl_db_console_debug_level;
+                       acpi_gbl_db_console_debug_level =
+                           strtoul(acpi_gbl_db_args[1], NULL, 16);
+                       acpi_os_printf
+                           ("Debug Level for console output was %8.8lX, now %8.8lX\n",
+                            temp, acpi_gbl_db_console_debug_level);
+               } else {
+                       temp = acpi_gbl_db_debug_level;
+                       acpi_gbl_db_debug_level =
+                           strtoul(acpi_gbl_db_args[1], NULL, 16);
+                       acpi_os_printf
+                           ("Debug Level for file output was %8.8lX, now %8.8lX\n",
+                            temp, acpi_gbl_db_debug_level);
+               }
+               break;
+
+       case CMD_LIST:
+
+               acpi_db_disassemble_aml(acpi_gbl_db_args[1], op);
+               break;
+
+       case CMD_LOCKS:
+
+               acpi_db_display_locks();
+               break;
+
+       case CMD_LOCALS:
+
+               acpi_db_display_locals();
+               break;
+
+       case CMD_METHODS:
+
+               status = acpi_db_display_objects("METHOD", acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_NAMESPACE:
+
+               acpi_db_dump_namespace(acpi_gbl_db_args[1],
+                                      acpi_gbl_db_args[2]);
+               break;
+
+       case CMD_NOTIFY:
+
+               temp = strtoul(acpi_gbl_db_args[2], NULL, 0);
+               acpi_db_send_notify(acpi_gbl_db_args[1], temp);
+               break;
+
+       case CMD_OBJECTS:
+
+               acpi_ut_strupr(acpi_gbl_db_args[1]);
+               status =
+                   acpi_db_display_objects(acpi_gbl_db_args[1],
+                                           acpi_gbl_db_args[2]);
+               break;
+
+       case CMD_OSI:
+
+               acpi_db_display_interfaces(acpi_gbl_db_args[1],
+                                          acpi_gbl_db_args[2]);
+               break;
+
+       case CMD_OWNER:
+
+               acpi_db_dump_namespace_by_owner(acpi_gbl_db_args[1],
+                                               acpi_gbl_db_args[2]);
+               break;
+
+       case CMD_PATHS:
+
+               acpi_db_dump_namespace_paths();
+               break;
+
+       case CMD_PREFIX:
+
+               acpi_db_set_scope(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_REFERENCES:
+
+               acpi_db_find_references(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_RESOURCES:
+
+               acpi_db_display_resources(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_RESULTS:
+
+               acpi_db_display_results();
+               break;
+
+       case CMD_SET:
+
+               acpi_db_set_method_data(acpi_gbl_db_args[1],
+                                       acpi_gbl_db_args[2],
+                                       acpi_gbl_db_args[3]);
+               break;
+
+       case CMD_STATS:
+
+               status = acpi_db_display_statistics(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_STOP:
+
+               return (AE_NOT_IMPLEMENTED);
+
+       case CMD_TABLES:
+
+               acpi_db_display_table_info(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_TEMPLATE:
+
+               acpi_db_display_template(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_TRACE:
+
+               acpi_db_trace(acpi_gbl_db_args[1], acpi_gbl_db_args[2],
+                             acpi_gbl_db_args[3]);
+               break;
+
+       case CMD_TREE:
+
+               acpi_db_display_calling_tree();
+               break;
+
+       case CMD_TYPE:
+
+               acpi_db_display_object_type(acpi_gbl_db_args[1]);
+               break;
+
+#ifdef ACPI_APPLICATION
+
+               /* Hardware simulation commands. */
+
+       case CMD_ENABLEACPI:
+#if (!ACPI_REDUCED_HARDWARE)
+
+               status = acpi_enable();
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("AcpiEnable failed (Status=%X)\n",
+                                      status);
+                       return (status);
+               }
+#endif                         /* !ACPI_REDUCED_HARDWARE */
+               break;
+
+       case CMD_EVENT:
+
+               acpi_os_printf("Event command not implemented\n");
+               break;
+
+       case CMD_GPE:
+
+               acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
+               break;
+
+       case CMD_GPES:
+
+               acpi_db_display_gpes();
+               break;
+
+       case CMD_SCI:
+
+               acpi_db_generate_sci();
+               break;
+
+       case CMD_SLEEP:
+
+               status = acpi_db_sleep(acpi_gbl_db_args[1]);
+               break;
+
+               /* File I/O commands. */
+
+       case CMD_CLOSE:
+
+               acpi_db_close_debug_file();
+               break;
+
+       case CMD_LOAD:
+
+               status =
+                   acpi_db_get_table_from_file(acpi_gbl_db_args[1], NULL,
+                                               FALSE);
+               break;
+
+       case CMD_OPEN:
+
+               acpi_db_open_debug_file(acpi_gbl_db_args[1]);
+               break;
+
+               /* User space commands. */
+
+       case CMD_TERMINATE:
+
+               acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+               acpi_ut_subsystem_shutdown();
+
+               /*
+                * TBD: [Restructure] Need some way to re-initialize without
+                * re-creating the semaphores!
+                */
+
+               acpi_gbl_db_terminate_loop = TRUE;
+               /*  acpi_initialize (NULL); */
+               break;
+
+       case CMD_THREADS:
+
+               acpi_db_create_execution_threads(acpi_gbl_db_args[1],
+                                                acpi_gbl_db_args[2],
+                                                acpi_gbl_db_args[3]);
+               break;
+
+               /* Debug test commands. */
+
+       case CMD_PREDEFINED:
+
+               acpi_db_check_predefined_names();
+               break;
+
+       case CMD_TEST:
+
+               acpi_db_execute_test(acpi_gbl_db_args[1]);
+               break;
+
+       case CMD_UNLOAD:
+
+               acpi_db_unload_acpi_table(acpi_gbl_db_args[1]);
+               break;
+#endif
+
+       case CMD_EXIT:
+       case CMD_QUIT:
+
+               if (op) {
+                       acpi_os_printf("Method execution terminated\n");
+                       return (AE_CTRL_TERMINATE);
+               }
+
+               if (!acpi_gbl_db_output_to_file) {
+                       acpi_dbg_level = ACPI_DEBUG_DEFAULT;
+               }
+#ifdef ACPI_APPLICATION
+               acpi_db_close_debug_file();
+#endif
+               acpi_gbl_db_terminate_loop = TRUE;
+               return (AE_CTRL_TERMINATE);
+
+       case CMD_NOT_FOUND:
+       default:
+
+               acpi_os_printf("%s: unknown command\n", acpi_gbl_db_args[0]);
+               return (AE_CTRL_TRUE);
+       }
+
+       if (ACPI_SUCCESS(status)) {
+               status = AE_CTRL_TRUE;
+       }
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_thread
+ *
+ * PARAMETERS:  context         - Not used
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context)
+{
+       acpi_status status = AE_OK;
+       acpi_status Mstatus;
+
+       while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) {
+               acpi_gbl_method_executing = FALSE;
+               acpi_gbl_step_to_next_call = FALSE;
+
+               Mstatus = acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
+                                               ACPI_WAIT_FOREVER);
+               if (ACPI_FAILURE(Mstatus)) {
+                       return;
+               }
+
+               status =
+                   acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL);
+
+               acpi_os_release_mutex(acpi_gbl_db_command_complete);
+       }
+       acpi_gbl_db_threads_terminated = TRUE;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_single_thread
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+static void acpi_db_single_thread(void)
+{
+
+       acpi_gbl_method_executing = FALSE;
+       acpi_gbl_step_to_next_call = FALSE;
+
+       (void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_user_commands
+ *
+ * PARAMETERS:  prompt              - User prompt (depends on mode)
+ *              op                  - Current executing parse op
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Command line execution for the AML debugger. Commands are
+ *              matched and dispatched here.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
+{
+       acpi_status status = AE_OK;
+
+       acpi_os_printf("\n");
+
+       /* TBD: [Restructure] Need a separate command line buffer for step mode */
+
+       while (!acpi_gbl_db_terminate_loop) {
+
+               /* Force output to console until a command is entered */
+
+               acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+
+               /* Different prompt if method is executing */
+
+               if (!acpi_gbl_method_executing) {
+                       acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+               } else {
+                       acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+               }
+
+               /* Get the user input line */
+
+               status = acpi_os_get_line(acpi_gbl_db_line_buf,
+                                         ACPI_DB_LINE_BUFFER_SIZE, NULL);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "While parsing command line"));
+                       return (status);
+               }
+
+               /* Check for single or multithreaded debug */
+
+               if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
+                       /*
+                        * Signal the debug thread that we have a command to execute,
+                        * and wait for the command to complete.
+                        */
+                       acpi_os_release_mutex(acpi_gbl_db_command_ready);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+
+                       status =
+                           acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
+                                                 ACPI_WAIT_FOREVER);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+               } else {
+                       /* Just call to the command line interpreter */
+
+                       acpi_db_single_thread();
+               }
+       }
+
+       return (status);
+}
diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c
new file mode 100644 (file)
index 0000000..01e5a71
--- /dev/null
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ *
+ * Module Name: dbmethod - Debug commands for control methods
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "acparser.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbmethod")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_breakpoint
+ *
+ * PARAMETERS:  location            - AML offset of breakpoint
+ *              walk_state          - Current walk info
+ *              op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a breakpoint in a control method at the specified
+ *              AML offset
+ *
+ ******************************************************************************/
+void
+acpi_db_set_method_breakpoint(char *location,
+                             struct acpi_walk_state *walk_state,
+                             union acpi_parse_object *op)
+{
+       u32 address;
+       u32 aml_offset;
+
+       if (!op) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       /* Get and verify the breakpoint address */
+
+       address = strtoul(location, NULL, 16);
+       aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
+                                       walk_state->parser_state.aml_start);
+       if (address <= aml_offset) {
+               acpi_os_printf("Breakpoint %X is beyond current address %X\n",
+                              address, aml_offset);
+       }
+
+       /* Save breakpoint in current walk */
+
+       walk_state->user_breakpoint = address;
+       acpi_os_printf("Breakpoint set at AML offset %X\n", address);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_call_breakpoint
+ *
+ * PARAMETERS:  op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a breakpoint in a control method at the specified
+ *              AML offset
+ *
+ ******************************************************************************/
+
+void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)
+{
+
+       if (!op) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       acpi_gbl_step_to_next_call = TRUE;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_data
+ *
+ * PARAMETERS:  type_arg        - L for local, A for argument
+ *              index_arg       - which one
+ *              value_arg       - Value to set.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a local or argument for the running control method.
+ *              NOTE: only object supported is Number.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)
+{
+       char type;
+       u32 index;
+       u32 value;
+       struct acpi_walk_state *walk_state;
+       union acpi_operand_object *obj_desc;
+       acpi_status status;
+       struct acpi_namespace_node *node;
+
+       /* Validate type_arg */
+
+       acpi_ut_strupr(type_arg);
+       type = type_arg[0];
+       if ((type != 'L') && (type != 'A') && (type != 'N')) {
+               acpi_os_printf("Invalid SET operand: %s\n", type_arg);
+               return;
+       }
+
+       value = strtoul(value_arg, NULL, 16);
+
+       if (type == 'N') {
+               node = acpi_db_convert_to_node(index_arg);
+               if (!node) {
+                       return;
+               }
+
+               if (node->type != ACPI_TYPE_INTEGER) {
+                       acpi_os_printf("Can only set Integer nodes\n");
+                       return;
+               }
+               obj_desc = node->object;
+               obj_desc->integer.value = value;
+               return;
+       }
+
+       /* Get the index and value */
+
+       index = strtoul(index_arg, NULL, 16);
+
+       walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+       if (!walk_state) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       /* Create and initialize the new object */
+
+       obj_desc = acpi_ut_create_integer_object((u64)value);
+       if (!obj_desc) {
+               acpi_os_printf("Could not create an internal object\n");
+               return;
+       }
+
+       /* Store the new object into the target */
+
+       switch (type) {
+       case 'A':
+
+               /* Set a method argument */
+
+               if (index > ACPI_METHOD_MAX_ARG) {
+                       acpi_os_printf("Arg%u - Invalid argument name\n",
+                                      index);
+                       goto cleanup;
+               }
+
+               status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,
+                                                      index, obj_desc,
+                                                      walk_state);
+               if (ACPI_FAILURE(status)) {
+                       goto cleanup;
+               }
+
+               obj_desc = walk_state->arguments[index].object;
+
+               acpi_os_printf("Arg%u: ", index);
+               acpi_db_display_internal_object(obj_desc, walk_state);
+               break;
+
+       case 'L':
+
+               /* Set a method local */
+
+               if (index > ACPI_METHOD_MAX_LOCAL) {
+                       acpi_os_printf
+                           ("Local%u - Invalid local variable name\n", index);
+                       goto cleanup;
+               }
+
+               status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,
+                                                      index, obj_desc,
+                                                      walk_state);
+               if (ACPI_FAILURE(status)) {
+                       goto cleanup;
+               }
+
+               obj_desc = walk_state->local_variables[index].object;
+
+               acpi_os_printf("Local%u: ", index);
+               acpi_db_display_internal_object(obj_desc, walk_state);
+               break;
+
+       default:
+
+               break;
+       }
+
+cleanup:
+       acpi_ut_remove_reference(obj_desc);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_disassemble_aml
+ *
+ * PARAMETERS:  statements          - Number of statements to disassemble
+ *              op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
+ *              of statements specified.
+ *
+ ******************************************************************************/
+
+void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)
+{
+       u32 num_statements = 8;
+
+       if (!op) {
+               acpi_os_printf("There is no method currently executing\n");
+               return;
+       }
+
+       if (statements) {
+               num_statements = strtoul(statements, NULL, 0);
+       }
+#ifdef ACPI_DISASSEMBLER
+       acpi_dm_disassemble(NULL, op, num_statements);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_disassemble_method
+ *
+ * PARAMETERS:  name            - Name of control method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
+ *              of statements specified.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_disassemble_method(char *name)
+{
+       acpi_status status;
+       union acpi_parse_object *op;
+       struct acpi_walk_state *walk_state;
+       union acpi_operand_object *obj_desc;
+       struct acpi_namespace_node *method;
+
+       method = acpi_db_convert_to_node(name);
+       if (!method) {
+               return (AE_BAD_PARAMETER);
+       }
+
+       if (method->type != ACPI_TYPE_METHOD) {
+               ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",
+                           name, acpi_ut_get_type_name(method->type)));
+               return (AE_BAD_PARAMETER);
+       }
+
+       obj_desc = method->object;
+
+       op = acpi_ps_create_scope_op(obj_desc->method.aml_start);
+       if (!op) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Create and initialize a new walk state */
+
+       walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);
+       if (!walk_state) {
+               return (AE_NO_MEMORY);
+       }
+
+       status = acpi_ds_init_aml_walk(walk_state, op, NULL,
+                                      obj_desc->method.aml_start,
+                                      obj_desc->method.aml_length, NULL,
+                                      ACPI_IMODE_LOAD_PASS1);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
+       walk_state->owner_id = obj_desc->method.owner_id;
+
+       /* Push start scope on scope stack and make it current */
+
+       status = acpi_ds_scope_stack_push(method, method->type, walk_state);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Parse the entire method AML including deferred operators */
+
+       walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;
+       walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
+
+       status = acpi_ps_parse_aml(walk_state);
+
+#ifdef ACPI_DISASSEMBLER
+       (void)acpi_dm_parse_deferred_ops(op);
+
+       /* Now we can disassemble the method */
+
+       acpi_gbl_dm_opt_verbose = FALSE;
+       acpi_dm_disassemble(NULL, op, 0);
+       acpi_gbl_dm_opt_verbose = TRUE;
+#endif
+
+       acpi_ps_delete_parse_tree(op);
+
+       /* Method cleanup */
+
+       acpi_ns_delete_namespace_subtree(method);
+       acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
+       acpi_ut_release_owner_id(&obj_desc->method.owner_id);
+       return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c
new file mode 100644 (file)
index 0000000..04ff1eb
--- /dev/null
@@ -0,0 +1,947 @@
+/*******************************************************************************
+ *
+ * Module Name: dbnames - Debugger commands for the acpi namespace
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbnames")
+
+/* Local prototypes */
+static acpi_status
+acpi_db_walk_and_match_name(acpi_handle obj_handle,
+                           u32 nesting_level,
+                           void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_predefined_names(acpi_handle obj_handle,
+                                 u32 nesting_level,
+                                 void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_specific_objects(acpi_handle obj_handle,
+                                 u32 nesting_level,
+                                 void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_object_counts(acpi_handle obj_handle,
+                              u32 nesting_level,
+                              void *context, void **return_value);
+
+static acpi_status
+acpi_db_integrity_walk(acpi_handle obj_handle,
+                      u32 nesting_level, void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_references(acpi_handle obj_handle,
+                           u32 nesting_level,
+                           void *context, void **return_value);
+
+static acpi_status
+acpi_db_bus_walk(acpi_handle obj_handle,
+                u32 nesting_level, void *context, void **return_value);
+
+/*
+ * Arguments for the Objects command
+ * These object types map directly to the ACPI_TYPES
+ */
+static struct acpi_db_argument_info acpi_db_object_types[] = {
+       {"ANY"},
+       {"INTEGERS"},
+       {"STRINGS"},
+       {"BUFFERS"},
+       {"PACKAGES"},
+       {"FIELDS"},
+       {"DEVICES"},
+       {"EVENTS"},
+       {"METHODS"},
+       {"MUTEXES"},
+       {"REGIONS"},
+       {"POWERRESOURCES"},
+       {"PROCESSORS"},
+       {"THERMALZONES"},
+       {"BUFFERFIELDS"},
+       {"DDBHANDLES"},
+       {"DEBUG"},
+       {"REGIONFIELDS"},
+       {"BANKFIELDS"},
+       {"INDEXFIELDS"},
+       {"REFERENCES"},
+       {"ALIASES"},
+       {"METHODALIASES"},
+       {"NOTIFY"},
+       {"ADDRESSHANDLER"},
+       {"RESOURCE"},
+       {"RESOURCEFIELD"},
+       {"SCOPES"},
+       {NULL}                  /* Must be null terminated */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_scope
+ *
+ * PARAMETERS:  name                - New scope path
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Set the "current scope" as maintained by this utility.
+ *              The scope is used as a prefix to ACPI paths.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_scope(char *name)
+{
+       acpi_status status;
+       struct acpi_namespace_node *node;
+
+       if (!name || name[0] == 0) {
+               acpi_os_printf("Current scope: %s\n", acpi_gbl_db_scope_buf);
+               return;
+       }
+
+       acpi_db_prep_namestring(name);
+
+       if (ACPI_IS_ROOT_PREFIX(name[0])) {
+
+               /* Validate new scope from the root */
+
+               status = acpi_ns_get_node(acpi_gbl_root_node, name,
+                                         ACPI_NS_NO_UPSEARCH, &node);
+               if (ACPI_FAILURE(status)) {
+                       goto error_exit;
+               }
+
+               acpi_gbl_db_scope_buf[0] = 0;
+       } else {
+               /* Validate new scope relative to old scope */
+
+               status = acpi_ns_get_node(acpi_gbl_db_scope_node, name,
+                                         ACPI_NS_NO_UPSEARCH, &node);
+               if (ACPI_FAILURE(status)) {
+                       goto error_exit;
+               }
+       }
+
+       /* Build the final pathname */
+
+       if (acpi_ut_safe_strcat
+           (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), name)) {
+               status = AE_BUFFER_OVERFLOW;
+               goto error_exit;
+       }
+
+       if (acpi_ut_safe_strcat
+           (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), "\\")) {
+               status = AE_BUFFER_OVERFLOW;
+               goto error_exit;
+       }
+
+       acpi_gbl_db_scope_node = node;
+       acpi_os_printf("New scope: %s\n", acpi_gbl_db_scope_buf);
+       return;
+
+error_exit:
+
+       acpi_os_printf("Could not attach scope: %s, %s\n",
+                      name, acpi_format_exception(status));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace
+ *
+ * PARAMETERS:  start_arg       - Node to begin namespace dump
+ *              depth_arg       - Maximum tree depth to be dumped
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed
+ *              with type and other information.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace(char *start_arg, char *depth_arg)
+{
+       acpi_handle subtree_entry = acpi_gbl_root_node;
+       u32 max_depth = ACPI_UINT32_MAX;
+
+       /* No argument given, just start at the root and dump entire namespace */
+
+       if (start_arg) {
+               subtree_entry = acpi_db_convert_to_node(start_arg);
+               if (!subtree_entry) {
+                       return;
+               }
+
+               /* Now we can check for the depth argument */
+
+               if (depth_arg) {
+                       max_depth = strtoul(depth_arg, NULL, 0);
+               }
+       }
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+       acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n",
+                      ((struct acpi_namespace_node *)subtree_entry)->name.
+                      ascii, subtree_entry);
+
+       /* Display the subtree */
+
+       acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+       acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth,
+                            ACPI_OWNER_ID_MAX, subtree_entry);
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace_paths
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump entire namespace with full object pathnames and object
+ *              type information. Alternative to "namespace" command.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace_paths(void)
+{
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+       acpi_os_printf("ACPI Namespace (from root):\n");
+
+       /* Display the entire namespace */
+
+       acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+       acpi_ns_dump_object_paths(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY,
+                                 ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX,
+                                 acpi_gbl_root_node);
+
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace_by_owner
+ *
+ * PARAMETERS:  owner_arg       - Owner ID whose nodes will be displayed
+ *              depth_arg       - Maximum tree depth to be dumped
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump elements of the namespace that are owned by the owner_id.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg)
+{
+       acpi_handle subtree_entry = acpi_gbl_root_node;
+       u32 max_depth = ACPI_UINT32_MAX;
+       acpi_owner_id owner_id;
+
+       owner_id = (acpi_owner_id) strtoul(owner_arg, NULL, 0);
+
+       /* Now we can check for the depth argument */
+
+       if (depth_arg) {
+               max_depth = strtoul(depth_arg, NULL, 0);
+       }
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+       acpi_os_printf("ACPI Namespace by owner %X:\n", owner_id);
+
+       /* Display the subtree */
+
+       acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+       acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth,
+                            owner_id, subtree_entry);
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_and_match_name
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Find a particular name/names within the namespace. Wildcards
+ *              are supported -- '?' matches any character.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_and_match_name(acpi_handle obj_handle,
+                           u32 nesting_level,
+                           void *context, void **return_value)
+{
+       acpi_status status;
+       char *requested_name = (char *)context;
+       u32 i;
+       struct acpi_buffer buffer;
+       struct acpi_walk_info info;
+
+       /* Check for a name match */
+
+       for (i = 0; i < 4; i++) {
+
+               /* Wildcard support */
+
+               if ((requested_name[i] != '?') &&
+                   (requested_name[i] != ((struct acpi_namespace_node *)
+                                          obj_handle)->name.ascii[i])) {
+
+                       /* No match, just exit */
+
+                       return (AE_OK);
+               }
+       }
+
+       /* Get the full pathname to this object */
+
+       buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could Not get pathname for object %p\n",
+                              obj_handle);
+       } else {
+               info.owner_id = ACPI_OWNER_ID_MAX;
+               info.debug_level = ACPI_UINT32_MAX;
+               info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+
+               acpi_os_printf("%32s", (char *)buffer.pointer);
+               (void)acpi_ns_dump_one_object(obj_handle, nesting_level, &info,
+                                             NULL);
+               ACPI_FREE(buffer.pointer);
+       }
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_find_name_in_namespace
+ *
+ * PARAMETERS:  name_arg        - The 4-character ACPI name to find.
+ *                                wildcards are supported.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Search the namespace for a given name (with wildcards)
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_find_name_in_namespace(char *name_arg)
+{
+       char acpi_name[5] = "____";
+       char *acpi_name_ptr = acpi_name;
+
+       if (strlen(name_arg) > ACPI_NAME_SIZE) {
+               acpi_os_printf("Name must be no longer than 4 characters\n");
+               return (AE_OK);
+       }
+
+       /* Pad out name with underscores as necessary to create a 4-char name */
+
+       acpi_ut_strupr(name_arg);
+       while (*name_arg) {
+               *acpi_name_ptr = *name_arg;
+               acpi_name_ptr++;
+               name_arg++;
+       }
+
+       /* Walk the namespace from the root */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX, acpi_db_walk_and_match_name,
+                                 NULL, acpi_name, NULL);
+
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_predefined_names
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Detect and display predefined ACPI names (names that start with
+ *              an underscore)
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_predefined_names(acpi_handle obj_handle,
+                                 u32 nesting_level,
+                                 void *context, void **return_value)
+{
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+       u32 *count = (u32 *)context;
+       const union acpi_predefined_info *predefined;
+       const union acpi_predefined_info *package = NULL;
+       char *pathname;
+       char string_buffer[48];
+
+       predefined = acpi_ut_match_predefined_method(node->name.ascii);
+       if (!predefined) {
+               return (AE_OK);
+       }
+
+       pathname = acpi_ns_get_external_pathname(node);
+       if (!pathname) {
+               return (AE_OK);
+       }
+
+       /* If method returns a package, the info is in the next table entry */
+
+       if (predefined->info.expected_btypes & ACPI_RTYPE_PACKAGE) {
+               package = predefined + 1;
+       }
+
+       acpi_ut_get_expected_return_types(string_buffer,
+                                         predefined->info.expected_btypes);
+
+       acpi_os_printf("%-32s Arguments %X, Return Types: %s", pathname,
+                      METHOD_GET_ARG_COUNT(predefined->info.argument_list),
+                      string_buffer);
+
+       if (package) {
+               acpi_os_printf(" (PkgType %2.2X, ObjType %2.2X, Count %2.2X)",
+                              package->ret_info.type,
+                              package->ret_info.object_type1,
+                              package->ret_info.count1);
+       }
+
+       acpi_os_printf("\n");
+
+       /* Check that the declared argument count matches the ACPI spec */
+
+       acpi_ns_check_acpi_compliance(pathname, node, predefined);
+
+       ACPI_FREE(pathname);
+       (*count)++;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_check_predefined_names
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Validate all predefined names in the namespace
+ *
+ ******************************************************************************/
+
+void acpi_db_check_predefined_names(void)
+{
+       u32 count = 0;
+
+       /* Search all nodes in namespace */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX,
+                                 acpi_db_walk_for_predefined_names, NULL,
+                                 (void *)&count, NULL);
+
+       acpi_os_printf("Found %u predefined names in the namespace\n", count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_object_counts
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_object_counts(acpi_handle obj_handle,
+                              u32 nesting_level,
+                              void *context, void **return_value)
+{
+       struct acpi_object_info *info = (struct acpi_object_info *)context;
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+
+       if (node->type > ACPI_TYPE_NS_NODE_MAX) {
+               acpi_os_printf("[%4.4s]: Unknown object type %X\n",
+                              node->name.ascii, node->type);
+       } else {
+               info->types[node->type]++;
+       }
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_specific_objects
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_specific_objects(acpi_handle obj_handle,
+                                 u32 nesting_level,
+                                 void *context, void **return_value)
+{
+       struct acpi_walk_info *info = (struct acpi_walk_info *)context;
+       struct acpi_buffer buffer;
+       acpi_status status;
+
+       info->count++;
+
+       /* Get and display the full pathname to this object */
+
+       buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could Not get pathname for object %p\n",
+                              obj_handle);
+               return (AE_OK);
+       }
+
+       acpi_os_printf("%32s", (char *)buffer.pointer);
+       ACPI_FREE(buffer.pointer);
+
+       /* Dump short info about the object */
+
+       (void)acpi_ns_dump_one_object(obj_handle, nesting_level, info, NULL);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_objects
+ *
+ * PARAMETERS:  obj_type_arg        - Type of object to display
+ *              display_count_arg   - Max depth to display
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display objects in the namespace of the requested type
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg)
+{
+       struct acpi_walk_info info;
+       acpi_object_type type;
+       struct acpi_object_info *object_info;
+       u32 i;
+       u32 total_objects = 0;
+
+       /* No argument means display summary/count of all object types */
+
+       if (!obj_type_arg) {
+               object_info =
+                   ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info));
+
+               /* Walk the namespace from the root */
+
+               (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                         ACPI_UINT32_MAX,
+                                         acpi_db_walk_for_object_counts, NULL,
+                                         (void *)object_info, NULL);
+
+               acpi_os_printf("\nSummary of namespace objects:\n\n");
+
+               for (i = 0; i < ACPI_TOTAL_TYPES; i++) {
+                       acpi_os_printf("%8u %s\n", object_info->types[i],
+                                      acpi_ut_get_type_name(i));
+
+                       total_objects += object_info->types[i];
+               }
+
+               acpi_os_printf("\n%8u Total namespace objects\n\n",
+                              total_objects);
+
+               ACPI_FREE(object_info);
+               return (AE_OK);
+       }
+
+       /* Get the object type */
+
+       type = acpi_db_match_argument(obj_type_arg, acpi_db_object_types);
+       if (type == ACPI_TYPE_NOT_FOUND) {
+               acpi_os_printf("Invalid or unsupported argument\n");
+               return (AE_OK);
+       }
+
+       acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+       acpi_os_printf
+           ("Objects of type [%s] defined in the current ACPI Namespace:\n",
+            acpi_ut_get_type_name(type));
+
+       acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+
+       info.count = 0;
+       info.owner_id = ACPI_OWNER_ID_MAX;
+       info.debug_level = ACPI_UINT32_MAX;
+       info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+
+       /* Walk the namespace from the root */
+
+       (void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+                                 acpi_db_walk_for_specific_objects, NULL,
+                                 (void *)&info, NULL);
+
+       acpi_os_printf
+           ("\nFound %u objects of type [%s] in the current ACPI Namespace\n",
+            info.count, acpi_ut_get_type_name(type));
+
+       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_integrity_walk
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Examine one NS node for valid values.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_integrity_walk(acpi_handle obj_handle,
+                      u32 nesting_level, void *context, void **return_value)
+{
+       struct acpi_integrity_info *info =
+           (struct acpi_integrity_info *)context;
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+       union acpi_operand_object *object;
+       u8 alias = TRUE;
+
+       info->nodes++;
+
+       /* Verify the NS node, and dereference aliases */
+
+       while (alias) {
+               if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+                       acpi_os_printf
+                           ("Invalid Descriptor Type for Node %p [%s] - "
+                            "is %2.2X should be %2.2X\n", node,
+                            acpi_ut_get_descriptor_name(node),
+                            ACPI_GET_DESCRIPTOR_TYPE(node),
+                            ACPI_DESC_TYPE_NAMED);
+                       return (AE_OK);
+               }
+
+               if ((node->type == ACPI_TYPE_LOCAL_ALIAS) ||
+                   (node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+                       node = (struct acpi_namespace_node *)node->object;
+               } else {
+                       alias = FALSE;
+               }
+       }
+
+       if (node->type > ACPI_TYPE_LOCAL_MAX) {
+               acpi_os_printf("Invalid Object Type for Node %p, Type = %X\n",
+                              node, node->type);
+               return (AE_OK);
+       }
+
+       if (!acpi_ut_valid_acpi_name(node->name.ascii)) {
+               acpi_os_printf("Invalid AcpiName for Node %p\n", node);
+               return (AE_OK);
+       }
+
+       object = acpi_ns_get_attached_object(node);
+       if (object) {
+               info->objects++;
+               if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
+                       acpi_os_printf
+                           ("Invalid Descriptor Type for Object %p [%s]\n",
+                            object, acpi_ut_get_descriptor_name(object));
+               }
+       }
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_check_integrity
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Check entire namespace for data structure integrity
+ *
+ ******************************************************************************/
+
+void acpi_db_check_integrity(void)
+{
+       struct acpi_integrity_info info = { 0, 0 };
+
+       /* Search all nodes in namespace */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX, acpi_db_integrity_walk, NULL,
+                                 (void *)&info, NULL);
+
+       acpi_os_printf("Verified %u namespace nodes with %u Objects\n",
+                      info.nodes, info.objects);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_references
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Check if this namespace object refers to the target object
+ *              that is passed in as the context value.
+ *
+ * Note: Currently doesn't check subobjects within the Node's object
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_references(acpi_handle obj_handle,
+                           u32 nesting_level,
+                           void *context, void **return_value)
+{
+       union acpi_operand_object *obj_desc =
+           (union acpi_operand_object *)context;
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+
+       /* Check for match against the namespace node itself */
+
+       if (node == (void *)obj_desc) {
+               acpi_os_printf("Object is a Node [%4.4s]\n",
+                              acpi_ut_get_node_name(node));
+       }
+
+       /* Check for match against the object attached to the node */
+
+       if (acpi_ns_get_attached_object(node) == obj_desc) {
+               acpi_os_printf("Reference at Node->Object %p [%4.4s]\n",
+                              node, acpi_ut_get_node_name(node));
+       }
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_find_references
+ *
+ * PARAMETERS:  object_arg      - String with hex value of the object
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Search namespace for all references to the input object
+ *
+ ******************************************************************************/
+
+void acpi_db_find_references(char *object_arg)
+{
+       union acpi_operand_object *obj_desc;
+       acpi_size address;
+
+       /* Convert string to object pointer */
+
+       address = strtoul(object_arg, NULL, 16);
+       obj_desc = ACPI_TO_POINTER(address);
+
+       /* Search all nodes in namespace */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX, acpi_db_walk_for_references,
+                                 NULL, (void *)obj_desc, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_bus_walk
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display info about device objects that have a corresponding
+ *              _PRT method.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_bus_walk(acpi_handle obj_handle,
+                u32 nesting_level, void *context, void **return_value)
+{
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+       acpi_status status;
+       struct acpi_buffer buffer;
+       struct acpi_namespace_node *temp_node;
+       struct acpi_device_info *info;
+       u32 i;
+
+       if ((node->type != ACPI_TYPE_DEVICE) &&
+           (node->type != ACPI_TYPE_PROCESSOR)) {
+               return (AE_OK);
+       }
+
+       /* Exit if there is no _PRT under this device */
+
+       status = acpi_get_handle(node, METHOD_NAME__PRT,
+                                ACPI_CAST_PTR(acpi_handle, &temp_node));
+       if (ACPI_FAILURE(status)) {
+               return (AE_OK);
+       }
+
+       /* Get the full path to this device object */
+
+       buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could Not get pathname for object %p\n",
+                              obj_handle);
+               return (AE_OK);
+       }
+
+       status = acpi_get_object_info(obj_handle, &info);
+       if (ACPI_FAILURE(status)) {
+               return (AE_OK);
+       }
+
+       /* Display the full path */
+
+       acpi_os_printf("%-32s Type %X", (char *)buffer.pointer, node->type);
+       ACPI_FREE(buffer.pointer);
+
+       if (info->flags & ACPI_PCI_ROOT_BRIDGE) {
+               acpi_os_printf(" - Is PCI Root Bridge");
+       }
+       acpi_os_printf("\n");
+
+       /* _PRT info */
+
+       acpi_os_printf("_PRT: %p\n", temp_node);
+
+       /* Dump _ADR, _HID, _UID, _CID */
+
+       if (info->valid & ACPI_VALID_ADR) {
+               acpi_os_printf("_ADR: %8.8X%8.8X\n",
+                              ACPI_FORMAT_UINT64(info->address));
+       } else {
+               acpi_os_printf("_ADR: <Not Present>\n");
+       }
+
+       if (info->valid & ACPI_VALID_HID) {
+               acpi_os_printf("_HID: %s\n", info->hardware_id.string);
+       } else {
+               acpi_os_printf("_HID: <Not Present>\n");
+       }
+
+       if (info->valid & ACPI_VALID_UID) {
+               acpi_os_printf("_UID: %s\n", info->unique_id.string);
+       } else {
+               acpi_os_printf("_UID: <Not Present>\n");
+       }
+
+       if (info->valid & ACPI_VALID_CID) {
+               for (i = 0; i < info->compatible_id_list.count; i++) {
+                       acpi_os_printf("_CID: %s\n",
+                                      info->compatible_id_list.ids[i].string);
+               }
+       } else {
+               acpi_os_printf("_CID: <Not Present>\n");
+       }
+
+       ACPI_FREE(info);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_bus_info
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display info about system busses.
+ *
+ ******************************************************************************/
+
+void acpi_db_get_bus_info(void)
+{
+       /* Search all nodes in namespace */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX, acpi_db_bus_walk, NULL, NULL,
+                                 NULL);
+}
diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c
new file mode 100644 (file)
index 0000000..116f6db
--- /dev/null
@@ -0,0 +1,533 @@
+/*******************************************************************************
+ *
+ * Module Name: dbobject - ACPI object decode and display
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbobject")
+
+/* Local prototypes */
+static void acpi_db_decode_node(struct acpi_namespace_node *node);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_method_info
+ *
+ * PARAMETERS:  status          - Method execution status
+ *              walk_state      - Current state of the parse tree walk
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Called when a method has been aborted because of an error.
+ *              Dumps the method execution stack, and the method locals/args,
+ *              and disassembles the AML opcode that failed.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state)
+{
+       struct acpi_thread_state *thread;
+
+       /* Ignore control codes, they are not errors */
+
+       if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) {
+               return;
+       }
+
+       /* We may be executing a deferred opcode */
+
+       if (walk_state->deferred_node) {
+               acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+               return;
+       }
+
+       /*
+        * If there is no Thread, we are not actually executing a method.
+        * This can happen when the iASL compiler calls the interpreter
+        * to perform constant folding.
+        */
+       thread = walk_state->thread;
+       if (!thread) {
+               return;
+       }
+
+       /* Display the method locals and arguments */
+
+       acpi_os_printf("\n");
+       acpi_db_decode_locals(walk_state);
+       acpi_os_printf("\n");
+       acpi_db_decode_arguments(walk_state);
+       acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_internal_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of an internal object. Numbers/Strings/Buffers.
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc)
+{
+       u32 i;
+
+       if (!obj_desc) {
+               acpi_os_printf(" Uninitialized");
+               return;
+       }
+
+       if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+               acpi_os_printf(" %p [%s]", obj_desc,
+                              acpi_ut_get_descriptor_name(obj_desc));
+               return;
+       }
+
+       acpi_os_printf(" %s", acpi_ut_get_object_type_name(obj_desc));
+
+       switch (obj_desc->common.type) {
+       case ACPI_TYPE_INTEGER:
+
+               acpi_os_printf(" %8.8X%8.8X",
+                              ACPI_FORMAT_UINT64(obj_desc->integer.value));
+               break;
+
+       case ACPI_TYPE_STRING:
+
+               acpi_os_printf("(%u) \"%.24s",
+                              obj_desc->string.length,
+                              obj_desc->string.pointer);
+
+               if (obj_desc->string.length > 24) {
+                       acpi_os_printf("...");
+               } else {
+                       acpi_os_printf("\"");
+               }
+               break;
+
+       case ACPI_TYPE_BUFFER:
+
+               acpi_os_printf("(%u)", obj_desc->buffer.length);
+               for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) {
+                       acpi_os_printf(" %2.2X", obj_desc->buffer.pointer[i]);
+               }
+               break;
+
+       default:
+
+               acpi_os_printf(" %p", obj_desc);
+               break;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_node
+ *
+ * PARAMETERS:  node        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of a namespace node
+ *
+ ******************************************************************************/
+
+static void acpi_db_decode_node(struct acpi_namespace_node *node)
+{
+
+       acpi_os_printf("<Node>          Name %4.4s",
+                      acpi_ut_get_node_name(node));
+
+       if (node->flags & ANOBJ_METHOD_ARG) {
+               acpi_os_printf(" [Method Arg]");
+       }
+       if (node->flags & ANOBJ_METHOD_LOCAL) {
+               acpi_os_printf(" [Method Local]");
+       }
+
+       switch (node->type) {
+
+               /* These types have no attached object */
+
+       case ACPI_TYPE_DEVICE:
+
+               acpi_os_printf(" Device");
+               break;
+
+       case ACPI_TYPE_THERMAL:
+
+               acpi_os_printf(" Thermal Zone");
+               break;
+
+       default:
+
+               acpi_db_decode_internal_object(acpi_ns_get_attached_object
+                                              (node));
+               break;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_internal_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of an internal object
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_internal_object(union acpi_operand_object *obj_desc,
+                               struct acpi_walk_state *walk_state)
+{
+       u8 type;
+
+       acpi_os_printf("%p ", obj_desc);
+
+       if (!obj_desc) {
+               acpi_os_printf("<Null Object>\n");
+               return;
+       }
+
+       /* Decode the object type */
+
+       switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
+       case ACPI_DESC_TYPE_PARSER:
+
+               acpi_os_printf("<Parser> ");
+               break;
+
+       case ACPI_DESC_TYPE_NAMED:
+
+               acpi_db_decode_node((struct acpi_namespace_node *)obj_desc);
+               break;
+
+       case ACPI_DESC_TYPE_OPERAND:
+
+               type = obj_desc->common.type;
+               if (type > ACPI_TYPE_LOCAL_MAX) {
+                       acpi_os_printf(" Type %X [Invalid Type]", (u32)type);
+                       return;
+               }
+
+               /* Decode the ACPI object type */
+
+               switch (obj_desc->common.type) {
+               case ACPI_TYPE_LOCAL_REFERENCE:
+
+                       acpi_os_printf("[%s] ",
+                                      acpi_ut_get_reference_name(obj_desc));
+
+                       /* Decode the refererence */
+
+                       switch (obj_desc->reference.class) {
+                       case ACPI_REFCLASS_LOCAL:
+
+                               acpi_os_printf("%X ",
+                                              obj_desc->reference.value);
+                               if (walk_state) {
+                                       obj_desc = walk_state->local_variables
+                                           [obj_desc->reference.value].object;
+                                       acpi_os_printf("%p", obj_desc);
+                                       acpi_db_decode_internal_object
+                                           (obj_desc);
+                               }
+                               break;
+
+                       case ACPI_REFCLASS_ARG:
+
+                               acpi_os_printf("%X ",
+                                              obj_desc->reference.value);
+                               if (walk_state) {
+                                       obj_desc = walk_state->arguments
+                                           [obj_desc->reference.value].object;
+                                       acpi_os_printf("%p", obj_desc);
+                                       acpi_db_decode_internal_object
+                                           (obj_desc);
+                               }
+                               break;
+
+                       case ACPI_REFCLASS_INDEX:
+
+                               switch (obj_desc->reference.target_type) {
+                               case ACPI_TYPE_BUFFER_FIELD:
+
+                                       acpi_os_printf("%p",
+                                                      obj_desc->reference.
+                                                      object);
+                                       acpi_db_decode_internal_object
+                                           (obj_desc->reference.object);
+                                       break;
+
+                               case ACPI_TYPE_PACKAGE:
+
+                                       acpi_os_printf("%p",
+                                                      obj_desc->reference.
+                                                      where);
+                                       if (!obj_desc->reference.where) {
+                                               acpi_os_printf
+                                                   (" Uninitialized WHERE pointer");
+                                       } else {
+                                               acpi_db_decode_internal_object(*
+                                                                              (obj_desc->
+                                                                               reference.
+                                                                               where));
+                                       }
+                                       break;
+
+                               default:
+
+                                       acpi_os_printf
+                                           ("Unknown index target type");
+                                       break;
+                               }
+                               break;
+
+                       case ACPI_REFCLASS_REFOF:
+
+                               if (!obj_desc->reference.object) {
+                                       acpi_os_printf
+                                           ("Uninitialized reference subobject pointer");
+                                       break;
+                               }
+
+                               /* Reference can be to a Node or an Operand object */
+
+                               switch (ACPI_GET_DESCRIPTOR_TYPE
+                                       (obj_desc->reference.object)) {
+                               case ACPI_DESC_TYPE_NAMED:
+
+                                       acpi_db_decode_node(obj_desc->reference.
+                                                           object);
+                                       break;
+
+                               case ACPI_DESC_TYPE_OPERAND:
+
+                                       acpi_db_decode_internal_object
+                                           (obj_desc->reference.object);
+                                       break;
+
+                               default:
+                                       break;
+                               }
+                               break;
+
+                       case ACPI_REFCLASS_NAME:
+
+                               acpi_db_decode_node(obj_desc->reference.node);
+                               break;
+
+                       case ACPI_REFCLASS_DEBUG:
+                       case ACPI_REFCLASS_TABLE:
+
+                               acpi_os_printf("\n");
+                               break;
+
+                       default:        /* Unknown reference class */
+
+                               acpi_os_printf("%2.2X\n",
+                                              obj_desc->reference.class);
+                               break;
+                       }
+                       break;
+
+               default:
+
+                       acpi_os_printf("<Obj>          ");
+                       acpi_db_decode_internal_object(obj_desc);
+                       break;
+               }
+               break;
+
+       default:
+
+               acpi_os_printf("<Not a valid ACPI Object Descriptor> [%s]",
+                              acpi_ut_get_descriptor_name(obj_desc));
+               break;
+       }
+
+       acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_locals
+ *
+ * PARAMETERS:  walk_state      - State for current method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all locals for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_locals(struct acpi_walk_state *walk_state)
+{
+       u32 i;
+       union acpi_operand_object *obj_desc;
+       struct acpi_namespace_node *node;
+       u8 display_locals = FALSE;
+
+       obj_desc = walk_state->method_desc;
+       node = walk_state->method_node;
+
+       if (!node) {
+               acpi_os_printf
+                   ("No method node (Executing subtree for buffer or opregion)\n");
+               return;
+       }
+
+       if (node->type != ACPI_TYPE_METHOD) {
+               acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+               return;
+       }
+
+       /* Are any locals actually set? */
+
+       for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+               obj_desc = walk_state->local_variables[i].object;
+               if (obj_desc) {
+                       display_locals = TRUE;
+                       break;
+               }
+       }
+
+       /* If any are set, only display the ones that are set */
+
+       if (display_locals) {
+               acpi_os_printf
+                   ("\nInitialized Local Variables for method [%4.4s]:\n",
+                    acpi_ut_get_node_name(node));
+
+               for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+                       obj_desc = walk_state->local_variables[i].object;
+                       if (obj_desc) {
+                               acpi_os_printf("  Local%X: ", i);
+                               acpi_db_display_internal_object(obj_desc,
+                                                               walk_state);
+                       }
+               }
+       } else {
+               acpi_os_printf
+                   ("No Local Variables are initialized for method [%4.4s]\n",
+                    acpi_ut_get_node_name(node));
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_arguments
+ *
+ * PARAMETERS:  walk_state      - State for current method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all arguments for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_arguments(struct acpi_walk_state *walk_state)
+{
+       u32 i;
+       union acpi_operand_object *obj_desc;
+       struct acpi_namespace_node *node;
+       u8 display_args = FALSE;
+
+       node = walk_state->method_node;
+       obj_desc = walk_state->method_desc;
+
+       if (!node) {
+               acpi_os_printf
+                   ("No method node (Executing subtree for buffer or opregion)\n");
+               return;
+       }
+
+       if (node->type != ACPI_TYPE_METHOD) {
+               acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+               return;
+       }
+
+       /* Are any arguments actually set? */
+
+       for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+               obj_desc = walk_state->arguments[i].object;
+               if (obj_desc) {
+                       display_args = TRUE;
+                       break;
+               }
+       }
+
+       /* If any are set, only display the ones that are set */
+
+       if (display_args) {
+               acpi_os_printf("Initialized Arguments for Method [%4.4s]:  "
+                              "(%X arguments defined for method invocation)\n",
+                              acpi_ut_get_node_name(node),
+                              obj_desc->method.param_count);
+
+               for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+                       obj_desc = walk_state->arguments[i].object;
+                       if (obj_desc) {
+                               acpi_os_printf("  Arg%u:   ", i);
+                               acpi_db_display_internal_object(obj_desc,
+                                                               walk_state);
+                       }
+               }
+       } else {
+               acpi_os_printf
+                   ("No Arguments are initialized for method [%4.4s]\n",
+                    acpi_ut_get_node_name(node));
+       }
+}
diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c
new file mode 100644 (file)
index 0000000..4ba0a20
--- /dev/null
@@ -0,0 +1,546 @@
+/*******************************************************************************
+ *
+ * Module Name: dbstats - Generation and display of ACPI table statistics
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbstats")
+
+/* Local prototypes */
+static void acpi_db_count_namespace_objects(void);
+
+static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc);
+
+static acpi_status
+acpi_db_classify_one_object(acpi_handle obj_handle,
+                           u32 nesting_level,
+                           void *context, void **return_value);
+
+#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
+static void acpi_db_list_info(struct acpi_memory_list *list);
+#endif
+
+/*
+ * Statistics subcommands
+ */
+static struct acpi_db_argument_info acpi_db_stat_types[] = {
+       {"ALLOCATIONS"},
+       {"OBJECTS"},
+       {"MEMORY"},
+       {"MISC"},
+       {"TABLES"},
+       {"SIZES"},
+       {"STACK"},
+       {NULL}                  /* Must be null terminated */
+};
+
+#define CMD_STAT_ALLOCATIONS     0
+#define CMD_STAT_OBJECTS         1
+#define CMD_STAT_MEMORY          2
+#define CMD_STAT_MISC            3
+#define CMD_STAT_TABLES          4
+#define CMD_STAT_SIZES           5
+#define CMD_STAT_STACK           6
+
+#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_list_info
+ *
+ * PARAMETERS:  list            - Memory list/cache to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about the input memory list or cache.
+ *
+ ******************************************************************************/
+
+static void acpi_db_list_info(struct acpi_memory_list *list)
+{
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+       u32 outstanding;
+#endif
+
+       acpi_os_printf("\n%s\n", list->list_name);
+
+       /* max_depth > 0 indicates a cache object */
+
+       if (list->max_depth > 0) {
+               acpi_os_printf
+                   ("    Cache: [Depth    MaxD Avail  Size]                "
+                    "%8.2X %8.2X %8.2X %8.2X\n", list->current_depth,
+                    list->max_depth, list->max_depth - list->current_depth,
+                    (list->current_depth * list->object_size));
+       }
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+       if (list->max_depth > 0) {
+               acpi_os_printf
+                   ("    Cache: [Requests Hits Misses ObjSize]             "
+                    "%8.2X %8.2X %8.2X %8.2X\n", list->requests, list->hits,
+                    list->requests - list->hits, list->object_size);
+       }
+
+       outstanding = acpi_db_get_cache_info(list);
+
+       if (list->object_size) {
+               acpi_os_printf
+                   ("    Mem:   [Alloc    Free Max    CurSize Outstanding] "
+                    "%8.2X %8.2X %8.2X %8.2X %8.2X\n", list->total_allocated,
+                    list->total_freed, list->max_occupied,
+                    outstanding * list->object_size, outstanding);
+       } else {
+               acpi_os_printf
+                   ("    Mem:   [Alloc Free Max CurSize Outstanding Total] "
+                    "%8.2X %8.2X %8.2X %8.2X %8.2X %8.2X\n",
+                    list->total_allocated, list->total_freed,
+                    list->max_occupied, list->current_total_size, outstanding,
+                    list->total_size);
+       }
+#endif
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_enumerate_object
+ *
+ * PARAMETERS:  obj_desc            - Object to be counted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Add this object to the global counts, by object type.
+ *              Limited recursion handles subobjects and packages, and this
+ *              is probably acceptable within the AML debugger only.
+ *
+ ******************************************************************************/
+
+static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc)
+{
+       u32 i;
+
+       if (!obj_desc) {
+               return;
+       }
+
+       /* Enumerate this object first */
+
+       acpi_gbl_num_objects++;
+
+       if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
+               acpi_gbl_obj_type_count_misc++;
+       } else {
+               acpi_gbl_obj_type_count[obj_desc->common.type]++;
+       }
+
+       /* Count the sub-objects */
+
+       switch (obj_desc->common.type) {
+       case ACPI_TYPE_PACKAGE:
+
+               for (i = 0; i < obj_desc->package.count; i++) {
+                       acpi_db_enumerate_object(obj_desc->package.elements[i]);
+               }
+               break;
+
+       case ACPI_TYPE_DEVICE:
+
+               acpi_db_enumerate_object(obj_desc->device.notify_list[0]);
+               acpi_db_enumerate_object(obj_desc->device.notify_list[1]);
+               acpi_db_enumerate_object(obj_desc->device.handler);
+               break;
+
+       case ACPI_TYPE_BUFFER_FIELD:
+
+               if (acpi_ns_get_secondary_object(obj_desc)) {
+                       acpi_gbl_obj_type_count[ACPI_TYPE_BUFFER_FIELD]++;
+               }
+               break;
+
+       case ACPI_TYPE_REGION:
+
+               acpi_gbl_obj_type_count[ACPI_TYPE_LOCAL_REGION_FIELD]++;
+               acpi_db_enumerate_object(obj_desc->region.handler);
+               break;
+
+       case ACPI_TYPE_POWER:
+
+               acpi_db_enumerate_object(obj_desc->power_resource.
+                                        notify_list[0]);
+               acpi_db_enumerate_object(obj_desc->power_resource.
+                                        notify_list[1]);
+               break;
+
+       case ACPI_TYPE_PROCESSOR:
+
+               acpi_db_enumerate_object(obj_desc->processor.notify_list[0]);
+               acpi_db_enumerate_object(obj_desc->processor.notify_list[1]);
+               acpi_db_enumerate_object(obj_desc->processor.handler);
+               break;
+
+       case ACPI_TYPE_THERMAL:
+
+               acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[0]);
+               acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[1]);
+               acpi_db_enumerate_object(obj_desc->thermal_zone.handler);
+               break;
+
+       default:
+
+               break;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_classify_one_object
+ *
+ * PARAMETERS:  Callback for walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enumerate both the object descriptor (including subobjects) and
+ *              the parent namespace node.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_classify_one_object(acpi_handle obj_handle,
+                           u32 nesting_level,
+                           void *context, void **return_value)
+{
+       struct acpi_namespace_node *node;
+       union acpi_operand_object *obj_desc;
+       u32 type;
+
+       acpi_gbl_num_nodes++;
+
+       node = (struct acpi_namespace_node *)obj_handle;
+       obj_desc = acpi_ns_get_attached_object(node);
+
+       acpi_db_enumerate_object(obj_desc);
+
+       type = node->type;
+       if (type > ACPI_TYPE_NS_NODE_MAX) {
+               acpi_gbl_node_type_count_misc++;
+       } else {
+               acpi_gbl_node_type_count[type]++;
+       }
+
+       return (AE_OK);
+
+#ifdef ACPI_FUTURE_IMPLEMENTATION
+
+       /* TBD: These need to be counted during the initial parsing phase */
+
+       if (acpi_ps_is_named_op(op->opcode)) {
+               num_nodes++;
+       }
+
+       if (is_method) {
+               num_method_elements++;
+       }
+
+       num_grammar_elements++;
+       op = acpi_ps_get_depth_next(root, op);
+
+       size_of_parse_tree = (num_grammar_elements - num_method_elements) *
+           (u32)sizeof(union acpi_parse_object);
+       size_of_method_trees =
+           num_method_elements * (u32)sizeof(union acpi_parse_object);
+       size_of_node_entries =
+           num_nodes * (u32)sizeof(struct acpi_namespace_node);
+       size_of_acpi_objects =
+           num_nodes * (u32)sizeof(union acpi_operand_object);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_count_namespace_objects
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Count and classify the entire namespace, including all
+ *              namespace nodes and attached objects.
+ *
+ ******************************************************************************/
+
+static void acpi_db_count_namespace_objects(void)
+{
+       u32 i;
+
+       acpi_gbl_num_nodes = 0;
+       acpi_gbl_num_objects = 0;
+
+       acpi_gbl_obj_type_count_misc = 0;
+       for (i = 0; i < (ACPI_TYPE_NS_NODE_MAX - 1); i++) {
+               acpi_gbl_obj_type_count[i] = 0;
+               acpi_gbl_node_type_count[i] = 0;
+       }
+
+       (void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                    ACPI_UINT32_MAX, FALSE,
+                                    acpi_db_classify_one_object, NULL, NULL,
+                                    NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_statistics
+ *
+ * PARAMETERS:  type_arg        - Subcommand
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display various statistics
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_statistics(char *type_arg)
+{
+       u32 i;
+       u32 temp;
+
+       acpi_ut_strupr(type_arg);
+       temp = acpi_db_match_argument(type_arg, acpi_db_stat_types);
+       if (temp == ACPI_TYPE_NOT_FOUND) {
+               acpi_os_printf("Invalid or unsupported argument\n");
+               return (AE_OK);
+       }
+
+       switch (temp) {
+       case CMD_STAT_ALLOCATIONS:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+               acpi_ut_dump_allocation_info();
+#endif
+               break;
+
+       case CMD_STAT_TABLES:
+
+               acpi_os_printf("ACPI Table Information (not implemented):\n\n");
+               break;
+
+       case CMD_STAT_OBJECTS:
+
+               acpi_db_count_namespace_objects();
+
+               acpi_os_printf
+                   ("\nObjects defined in the current namespace:\n\n");
+
+               acpi_os_printf("%16.16s %10.10s %10.10s\n",
+                              "ACPI_TYPE", "NODES", "OBJECTS");
+
+               for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) {
+                       acpi_os_printf("%16.16s % 10ld% 10ld\n",
+                                      acpi_ut_get_type_name(i),
+                                      acpi_gbl_node_type_count[i],
+                                      acpi_gbl_obj_type_count[i]);
+               }
+               acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown",
+                              acpi_gbl_node_type_count_misc,
+                              acpi_gbl_obj_type_count_misc);
+
+               acpi_os_printf("%16.16s % 10ld% 10ld\n", "TOTALS:",
+                              acpi_gbl_num_nodes, acpi_gbl_num_objects);
+               break;
+
+       case CMD_STAT_MEMORY:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+               acpi_os_printf
+                   ("\n----Object Statistics (all in hex)---------\n");
+
+               acpi_db_list_info(acpi_gbl_global_list);
+               acpi_db_list_info(acpi_gbl_ns_node_list);
+#endif
+
+#ifdef ACPI_USE_LOCAL_CACHE
+               acpi_os_printf
+                   ("\n----Cache Statistics (all in hex)---------\n");
+               acpi_db_list_info(acpi_gbl_operand_cache);
+               acpi_db_list_info(acpi_gbl_ps_node_cache);
+               acpi_db_list_info(acpi_gbl_ps_node_ext_cache);
+               acpi_db_list_info(acpi_gbl_state_cache);
+#endif
+
+               break;
+
+       case CMD_STAT_MISC:
+
+               acpi_os_printf("\nMiscellaneous Statistics:\n\n");
+               acpi_os_printf("Calls to AcpiPsFind:.. ........% 7ld\n",
+                              acpi_gbl_ps_find_count);
+               acpi_os_printf("Calls to AcpiNsLookup:..........% 7ld\n",
+                              acpi_gbl_ns_lookup_count);
+
+               acpi_os_printf("\n");
+
+               acpi_os_printf("Mutex usage:\n\n");
+               for (i = 0; i < ACPI_NUM_MUTEX; i++) {
+                       acpi_os_printf("%-28s:     % 7ld\n",
+                                      acpi_ut_get_mutex_name(i),
+                                      acpi_gbl_mutex_info[i].use_count);
+               }
+               break;
+
+       case CMD_STAT_SIZES:
+
+               acpi_os_printf("\nInternal object sizes:\n\n");
+
+               acpi_os_printf("Common         %3d\n",
+                              sizeof(struct acpi_object_common));
+               acpi_os_printf("Number         %3d\n",
+                              sizeof(struct acpi_object_integer));
+               acpi_os_printf("String         %3d\n",
+                              sizeof(struct acpi_object_string));
+               acpi_os_printf("Buffer         %3d\n",
+                              sizeof(struct acpi_object_buffer));
+               acpi_os_printf("Package        %3d\n",
+                              sizeof(struct acpi_object_package));
+               acpi_os_printf("BufferField    %3d\n",
+                              sizeof(struct acpi_object_buffer_field));
+               acpi_os_printf("Device         %3d\n",
+                              sizeof(struct acpi_object_device));
+               acpi_os_printf("Event          %3d\n",
+                              sizeof(struct acpi_object_event));
+               acpi_os_printf("Method         %3d\n",
+                              sizeof(struct acpi_object_method));
+               acpi_os_printf("Mutex          %3d\n",
+                              sizeof(struct acpi_object_mutex));
+               acpi_os_printf("Region         %3d\n",
+                              sizeof(struct acpi_object_region));
+               acpi_os_printf("PowerResource  %3d\n",
+                              sizeof(struct acpi_object_power_resource));
+               acpi_os_printf("Processor      %3d\n",
+                              sizeof(struct acpi_object_processor));
+               acpi_os_printf("ThermalZone    %3d\n",
+                              sizeof(struct acpi_object_thermal_zone));
+               acpi_os_printf("RegionField    %3d\n",
+                              sizeof(struct acpi_object_region_field));
+               acpi_os_printf("BankField      %3d\n",
+                              sizeof(struct acpi_object_bank_field));
+               acpi_os_printf("IndexField     %3d\n",
+                              sizeof(struct acpi_object_index_field));
+               acpi_os_printf("Reference      %3d\n",
+                              sizeof(struct acpi_object_reference));
+               acpi_os_printf("Notify         %3d\n",
+                              sizeof(struct acpi_object_notify_handler));
+               acpi_os_printf("AddressSpace   %3d\n",
+                              sizeof(struct acpi_object_addr_handler));
+               acpi_os_printf("Extra          %3d\n",
+                              sizeof(struct acpi_object_extra));
+               acpi_os_printf("Data           %3d\n",
+                              sizeof(struct acpi_object_data));
+
+               acpi_os_printf("\n");
+
+               acpi_os_printf("ParseObject    %3d\n",
+                              sizeof(struct acpi_parse_obj_common));
+               acpi_os_printf("ParseObjectNamed %3d\n",
+                              sizeof(struct acpi_parse_obj_named));
+               acpi_os_printf("ParseObjectAsl %3d\n",
+                              sizeof(struct acpi_parse_obj_asl));
+               acpi_os_printf("OperandObject  %3d\n",
+                              sizeof(union acpi_operand_object));
+               acpi_os_printf("NamespaceNode  %3d\n",
+                              sizeof(struct acpi_namespace_node));
+               acpi_os_printf("AcpiObject     %3d\n",
+                              sizeof(union acpi_object));
+
+               acpi_os_printf("\n");
+
+               acpi_os_printf("Generic State  %3d\n",
+                              sizeof(union acpi_generic_state));
+               acpi_os_printf("Common State   %3d\n",
+                              sizeof(struct acpi_common_state));
+               acpi_os_printf("Control State  %3d\n",
+                              sizeof(struct acpi_control_state));
+               acpi_os_printf("Update State   %3d\n",
+                              sizeof(struct acpi_update_state));
+               acpi_os_printf("Scope State    %3d\n",
+                              sizeof(struct acpi_scope_state));
+               acpi_os_printf("Parse Scope    %3d\n",
+                              sizeof(struct acpi_pscope_state));
+               acpi_os_printf("Package State  %3d\n",
+                              sizeof(struct acpi_pkg_state));
+               acpi_os_printf("Thread State   %3d\n",
+                              sizeof(struct acpi_thread_state));
+               acpi_os_printf("Result Values  %3d\n",
+                              sizeof(struct acpi_result_values));
+               acpi_os_printf("Notify Info    %3d\n",
+                              sizeof(struct acpi_notify_info));
+               break;
+
+       case CMD_STAT_STACK:
+#if defined(ACPI_DEBUG_OUTPUT)
+
+               temp =
+                   (u32)ACPI_PTR_DIFF(acpi_gbl_entry_stack_pointer,
+                                      acpi_gbl_lowest_stack_pointer);
+
+               acpi_os_printf("\nSubsystem Stack Usage:\n\n");
+               acpi_os_printf("Entry Stack Pointer        %p\n",
+                              acpi_gbl_entry_stack_pointer);
+               acpi_os_printf("Lowest Stack Pointer       %p\n",
+                              acpi_gbl_lowest_stack_pointer);
+               acpi_os_printf("Stack Use                  %X (%u)\n", temp,
+                              temp);
+               acpi_os_printf("Deepest Procedure Nesting  %u\n",
+                              acpi_gbl_deepest_nesting);
+#endif
+               break;
+
+       default:
+
+               break;
+       }
+
+       acpi_os_printf("\n");
+       return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c
new file mode 100644 (file)
index 0000000..10ea8bf
--- /dev/null
@@ -0,0 +1,1057 @@
+/*******************************************************************************
+ *
+ * Module Name: dbtest - Various debug-related tests
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbtest")
+
+/* Local prototypes */
+static void acpi_db_test_all_objects(void);
+
+static acpi_status
+acpi_db_test_one_object(acpi_handle obj_handle,
+                       u32 nesting_level, void *context, void **return_value);
+
+static acpi_status
+acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length);
+
+static acpi_status
+acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length);
+
+static acpi_status
+acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length);
+
+static acpi_status
+acpi_db_read_from_object(struct acpi_namespace_node *node,
+                        acpi_object_type expected_type,
+                        union acpi_object **value);
+
+static acpi_status
+acpi_db_write_to_object(struct acpi_namespace_node *node,
+                       union acpi_object *value);
+
+static void acpi_db_evaluate_all_predefined_names(char *count_arg);
+
+static acpi_status
+acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle,
+                                    u32 nesting_level,
+                                    void *context, void **return_value);
+
+/*
+ * Test subcommands
+ */
+static struct acpi_db_argument_info acpi_db_test_types[] = {
+       {"OBJECTS"},
+       {"PREDEFINED"},
+       {NULL}                  /* Must be null terminated */
+};
+
+#define CMD_TEST_OBJECTS        0
+#define CMD_TEST_PREDEFINED     1
+
+#define BUFFER_FILL_VALUE       0xFF
+
+/*
+ * Support for the special debugger read/write control methods.
+ * These methods are installed into the current namespace and are
+ * used to read and write the various namespace objects. The point
+ * is to force the AML interpreter do all of the work.
+ */
+#define ACPI_DB_READ_METHOD     "\\_T98"
+#define ACPI_DB_WRITE_METHOD    "\\_T99"
+
+static acpi_handle read_handle = NULL;
+static acpi_handle write_handle = NULL;
+
+/* ASL Definitions of the debugger read/write control methods */
+
+#if 0
+definition_block("ssdt.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
+{
+       method(_T98, 1, not_serialized) {       /* Read */
+               return (de_ref_of(arg0))
+       }
+}
+
+definition_block("ssdt2.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
+{
+       method(_T99, 2, not_serialized) {       /* Write */
+               store(arg1, arg0)
+       }
+}
+#endif
+
+static unsigned char read_method_code[] = {
+       0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00, /* 00000000    "SSDT...." */
+       0x02, 0xC9, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00, /* 00000008    "..Intel." */
+       0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00, /* 00000010    "DEBUG..." */
+       0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C, /* 00000018    "....INTL" */
+       0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54, /* 00000020    "... .._T" */
+       0x39, 0x38, 0x01, 0xA4, 0x83, 0x68      /* 00000028    "98...h"   */
+};
+
+static unsigned char write_method_code[] = {
+       0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00, /* 00000000    "SSDT...." */
+       0x02, 0x15, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00, /* 00000008    "..Intel." */
+       0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00, /* 00000010    "DEBUG..." */
+       0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C, /* 00000018    "....INTL" */
+       0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54, /* 00000020    "... .._T" */
+       0x39, 0x39, 0x02, 0x70, 0x69, 0x68      /* 00000028    "99.pih"   */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_test
+ *
+ * PARAMETERS:  type_arg        - Subcommand
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute various debug tests.
+ *
+ * Note: Code is prepared for future expansion of the TEST command.
+ *
+ ******************************************************************************/
+
+void acpi_db_execute_test(char *type_arg)
+{
+       u32 temp;
+
+       acpi_ut_strupr(type_arg);
+       temp = acpi_db_match_argument(type_arg, acpi_db_test_types);
+       if (temp == ACPI_TYPE_NOT_FOUND) {
+               acpi_os_printf("Invalid or unsupported argument\n");
+               return;
+       }
+
+       switch (temp) {
+       case CMD_TEST_OBJECTS:
+
+               acpi_db_test_all_objects();
+               break;
+
+       case CMD_TEST_PREDEFINED:
+
+               acpi_db_evaluate_all_predefined_names(NULL);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_all_objects
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: This test implements the OBJECTS subcommand. It exercises the
+ *              namespace by reading/writing/comparing all data objects such
+ *              as integers, strings, buffers, fields, buffer fields, etc.
+ *
+ ******************************************************************************/
+
+static void acpi_db_test_all_objects(void)
+{
+       acpi_status status;
+
+       /* Install the debugger read-object control method if necessary */
+
+       if (!read_handle) {
+               status = acpi_install_method(read_method_code);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf
+                           ("%s, Could not install debugger read method\n",
+                            acpi_format_exception(status));
+                       return;
+               }
+
+               status =
+                   acpi_get_handle(NULL, ACPI_DB_READ_METHOD, &read_handle);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf
+                           ("Could not obtain handle for debug method %s\n",
+                            ACPI_DB_READ_METHOD);
+                       return;
+               }
+       }
+
+       /* Install the debugger write-object control method if necessary */
+
+       if (!write_handle) {
+               status = acpi_install_method(write_method_code);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf
+                           ("%s, Could not install debugger write method\n",
+                            acpi_format_exception(status));
+                       return;
+               }
+
+               status =
+                   acpi_get_handle(NULL, ACPI_DB_WRITE_METHOD, &write_handle);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf
+                           ("Could not obtain handle for debug method %s\n",
+                            ACPI_DB_WRITE_METHOD);
+                       return;
+               }
+       }
+
+       /* Walk the entire namespace, testing each supported named data object */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX, acpi_db_test_one_object,
+                                 NULL, NULL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_one_object
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test one namespace object. Supported types are Integer,
+ *              String, Buffer, buffer_field, and field_unit. All other object
+ *              types are simply ignored.
+ *
+ *              Note: Support for Packages is not implemented.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_one_object(acpi_handle obj_handle,
+                       u32 nesting_level, void *context, void **return_value)
+{
+       struct acpi_namespace_node *node;
+       union acpi_operand_object *obj_desc;
+       union acpi_operand_object *region_obj;
+       acpi_object_type local_type;
+       u32 bit_length = 0;
+       u32 byte_length = 0;
+       acpi_status status = AE_OK;
+
+       node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+       obj_desc = node->object;
+
+       /*
+        * For the supported types, get the actual bit length or
+        * byte length. Map the type to one of Integer/String/Buffer.
+        */
+       switch (node->type) {
+       case ACPI_TYPE_INTEGER:
+
+               /* Integer width is either 32 or 64 */
+
+               local_type = ACPI_TYPE_INTEGER;
+               bit_length = acpi_gbl_integer_bit_width;
+               break;
+
+       case ACPI_TYPE_STRING:
+
+               local_type = ACPI_TYPE_STRING;
+               byte_length = obj_desc->string.length;
+               break;
+
+       case ACPI_TYPE_BUFFER:
+
+               local_type = ACPI_TYPE_BUFFER;
+               byte_length = obj_desc->buffer.length;
+               bit_length = byte_length * 8;
+               break;
+
+       case ACPI_TYPE_FIELD_UNIT:
+       case ACPI_TYPE_BUFFER_FIELD:
+       case ACPI_TYPE_LOCAL_REGION_FIELD:
+       case ACPI_TYPE_LOCAL_INDEX_FIELD:
+       case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+               local_type = ACPI_TYPE_INTEGER;
+               if (obj_desc) {
+                       /*
+                        * Returned object will be a Buffer if the field length
+                        * is larger than the size of an Integer (32 or 64 bits
+                        * depending on the DSDT version).
+                        */
+                       bit_length = obj_desc->common_field.bit_length;
+                       byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
+                       if (bit_length > acpi_gbl_integer_bit_width) {
+                               local_type = ACPI_TYPE_BUFFER;
+                       }
+               }
+               break;
+
+       default:
+
+               /* Ignore all other types */
+
+               return (AE_OK);
+       }
+
+       /* Emit the common prefix: Type:Name */
+
+       acpi_os_printf("%14s: %4.4s",
+                      acpi_ut_get_type_name(node->type), node->name.ascii);
+       if (!obj_desc) {
+               acpi_os_printf(" Ignoring, no attached object\n");
+               return (AE_OK);
+       }
+
+       /*
+        * Check for unsupported region types. Note: acpi_exec simulates
+        * access to system_memory, system_IO, PCI_Config, and EC.
+        */
+       switch (node->type) {
+       case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+               region_obj = obj_desc->field.region_obj;
+               switch (region_obj->region.space_id) {
+               case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               case ACPI_ADR_SPACE_SYSTEM_IO:
+               case ACPI_ADR_SPACE_PCI_CONFIG:
+               case ACPI_ADR_SPACE_EC:
+
+                       break;
+
+               default:
+
+                       acpi_os_printf
+                           ("    %s space is not supported [%4.4s]\n",
+                            acpi_ut_get_region_name(region_obj->region.
+                                                    space_id),
+                            region_obj->region.node->name.ascii);
+                       return (AE_OK);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       /* At this point, we have resolved the object to one of the major types */
+
+       switch (local_type) {
+       case ACPI_TYPE_INTEGER:
+
+               status = acpi_db_test_integer_type(node, bit_length);
+               break;
+
+       case ACPI_TYPE_STRING:
+
+               status = acpi_db_test_string_type(node, byte_length);
+               break;
+
+       case ACPI_TYPE_BUFFER:
+
+               status = acpi_db_test_buffer_type(node, bit_length);
+               break;
+
+       default:
+
+               acpi_os_printf(" Ignoring, type not implemented (%2.2X)",
+                              local_type);
+               break;
+       }
+
+       switch (node->type) {
+       case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+               region_obj = obj_desc->field.region_obj;
+               acpi_os_printf(" (%s)",
+                              acpi_ut_get_region_name(region_obj->region.
+                                                      space_id));
+               break;
+
+       default:
+               break;
+       }
+
+       acpi_os_printf("\n");
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_integer_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              bit_length          - Actual length of the object. Used for
+ *                                    support of arbitrary length field_unit
+ *                                    and buffer_field objects.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an Integer-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length)
+{
+       union acpi_object *temp1 = NULL;
+       union acpi_object *temp2 = NULL;
+       union acpi_object *temp3 = NULL;
+       union acpi_object write_value;
+       u64 value_to_write;
+       acpi_status status;
+
+       if (bit_length > 64) {
+               acpi_os_printf(" Invalid length for an Integer: %u",
+                              bit_length);
+               return (AE_OK);
+       }
+
+       /* Read the original value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp1);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       acpi_os_printf(" (%4.4X/%3.3X) %8.8X%8.8X",
+                      bit_length, ACPI_ROUND_BITS_UP_TO_BYTES(bit_length),
+                      ACPI_FORMAT_UINT64(temp1->integer.value));
+
+       value_to_write = ACPI_UINT64_MAX >> (64 - bit_length);
+       if (temp1->integer.value == value_to_write) {
+               value_to_write = 0;
+       }
+
+       /* Write a new value */
+
+       write_value.type = ACPI_TYPE_INTEGER;
+       write_value.integer.value = value_to_write;
+       status = acpi_db_write_to_object(node, &write_value);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Ensure that we can read back the new value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp2);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       if (temp2->integer.value != value_to_write) {
+               acpi_os_printf(" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X",
+                              ACPI_FORMAT_UINT64(temp2->integer.value),
+                              ACPI_FORMAT_UINT64(value_to_write));
+       }
+
+       /* Write back the original value */
+
+       write_value.integer.value = temp1->integer.value;
+       status = acpi_db_write_to_object(node, &write_value);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Ensure that we can read back the original value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp3);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       if (temp3->integer.value != temp1->integer.value) {
+               acpi_os_printf(" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X",
+                              ACPI_FORMAT_UINT64(temp3->integer.value),
+                              ACPI_FORMAT_UINT64(temp1->integer.value));
+       }
+
+exit:
+       if (temp1) {
+               acpi_os_free(temp1);
+       }
+       if (temp2) {
+               acpi_os_free(temp2);
+       }
+       if (temp3) {
+               acpi_os_free(temp3);
+       }
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_buffer_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              bit_length          - Actual length of the object.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an Buffer-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length)
+{
+       union acpi_object *temp1 = NULL;
+       union acpi_object *temp2 = NULL;
+       union acpi_object *temp3 = NULL;
+       u8 *buffer;
+       union acpi_object write_value;
+       acpi_status status;
+       u32 byte_length;
+       u32 i;
+       u8 extra_bits;
+
+       byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
+       if (byte_length == 0) {
+               acpi_os_printf(" Ignoring zero length buffer");
+               return (AE_OK);
+       }
+
+       /* Allocate a local buffer */
+
+       buffer = ACPI_ALLOCATE_ZEROED(byte_length);
+       if (!buffer) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Read the original value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp1);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Emit a few bytes of the buffer */
+
+       acpi_os_printf(" (%4.4X/%3.3X)", bit_length, temp1->buffer.length);
+       for (i = 0; ((i < 4) && (i < byte_length)); i++) {
+               acpi_os_printf(" %2.2X", temp1->buffer.pointer[i]);
+       }
+       acpi_os_printf("... ");
+
+       /*
+        * Write a new value.
+        *
+        * Handle possible extra bits at the end of the buffer. Can
+        * happen for field_units larger than an integer, but the bit
+        * count is not an integral number of bytes. Zero out the
+        * unused bits.
+        */
+       memset(buffer, BUFFER_FILL_VALUE, byte_length);
+       extra_bits = bit_length % 8;
+       if (extra_bits) {
+               buffer[byte_length - 1] = ACPI_MASK_BITS_ABOVE(extra_bits);
+       }
+
+       write_value.type = ACPI_TYPE_BUFFER;
+       write_value.buffer.length = byte_length;
+       write_value.buffer.pointer = buffer;
+
+       status = acpi_db_write_to_object(node, &write_value);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Ensure that we can read back the new value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp2);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       if (memcmp(temp2->buffer.pointer, buffer, byte_length)) {
+               acpi_os_printf(" MISMATCH 2: New buffer value");
+       }
+
+       /* Write back the original value */
+
+       write_value.buffer.length = byte_length;
+       write_value.buffer.pointer = temp1->buffer.pointer;
+
+       status = acpi_db_write_to_object(node, &write_value);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Ensure that we can read back the original value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp3);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       if (memcmp(temp1->buffer.pointer, temp3->buffer.pointer, byte_length)) {
+               acpi_os_printf(" MISMATCH 3: While restoring original buffer");
+       }
+
+exit:
+       ACPI_FREE(buffer);
+       if (temp1) {
+               acpi_os_free(temp1);
+       }
+       if (temp2) {
+               acpi_os_free(temp2);
+       }
+       if (temp3) {
+               acpi_os_free(temp3);
+       }
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_string_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              byte_length         - Actual length of the object.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an String-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length)
+{
+       union acpi_object *temp1 = NULL;
+       union acpi_object *temp2 = NULL;
+       union acpi_object *temp3 = NULL;
+       char *value_to_write = "Test String from AML Debugger";
+       union acpi_object write_value;
+       acpi_status status;
+
+       /* Read the original value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp1);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       acpi_os_printf(" (%4.4X/%3.3X) \"%s\"", (temp1->string.length * 8),
+                      temp1->string.length, temp1->string.pointer);
+
+       /* Write a new value */
+
+       write_value.type = ACPI_TYPE_STRING;
+       write_value.string.length = strlen(value_to_write);
+       write_value.string.pointer = value_to_write;
+
+       status = acpi_db_write_to_object(node, &write_value);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Ensure that we can read back the new value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp2);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       if (strcmp(temp2->string.pointer, value_to_write)) {
+               acpi_os_printf(" MISMATCH 2: %s, expecting %s",
+                              temp2->string.pointer, value_to_write);
+       }
+
+       /* Write back the original value */
+
+       write_value.string.length = strlen(temp1->string.pointer);
+       write_value.string.pointer = temp1->string.pointer;
+
+       status = acpi_db_write_to_object(node, &write_value);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Ensure that we can read back the original value */
+
+       status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp3);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       if (strcmp(temp1->string.pointer, temp3->string.pointer)) {
+               acpi_os_printf(" MISMATCH 3: %s, expecting %s",
+                              temp3->string.pointer, temp1->string.pointer);
+       }
+
+exit:
+       if (temp1) {
+               acpi_os_free(temp1);
+       }
+       if (temp2) {
+               acpi_os_free(temp2);
+       }
+       if (temp3) {
+               acpi_os_free(temp3);
+       }
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_read_from_object
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              expected_type       - Object type expected from the read
+ *              value               - Where the value read is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Performs a read from the specified object by invoking the
+ *              special debugger control method that reads the object. Thus,
+ *              the AML interpreter is doing all of the work, increasing the
+ *              validity of the test.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_read_from_object(struct acpi_namespace_node *node,
+                        acpi_object_type expected_type,
+                        union acpi_object **value)
+{
+       union acpi_object *ret_value;
+       struct acpi_object_list param_objects;
+       union acpi_object params[2];
+       struct acpi_buffer return_obj;
+       acpi_status status;
+
+       params[0].type = ACPI_TYPE_LOCAL_REFERENCE;
+       params[0].reference.actual_type = node->type;
+       params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node);
+
+       param_objects.count = 1;
+       param_objects.pointer = params;
+
+       return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+       acpi_gbl_method_executing = TRUE;
+       status = acpi_evaluate_object(read_handle, NULL,
+                                     &param_objects, &return_obj);
+       acpi_gbl_method_executing = FALSE;
+
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not read from object, %s",
+                              acpi_format_exception(status));
+               return (status);
+       }
+
+       ret_value = (union acpi_object *)return_obj.pointer;
+
+       switch (ret_value->type) {
+       case ACPI_TYPE_INTEGER:
+       case ACPI_TYPE_BUFFER:
+       case ACPI_TYPE_STRING:
+               /*
+                * Did we receive the type we wanted? Most important for the
+                * Integer/Buffer case (when a field is larger than an Integer,
+                * it should return a Buffer).
+                */
+               if (ret_value->type != expected_type) {
+                       acpi_os_printf
+                           (" Type mismatch: Expected %s, Received %s",
+                            acpi_ut_get_type_name(expected_type),
+                            acpi_ut_get_type_name(ret_value->type));
+
+                       return (AE_TYPE);
+               }
+
+               *value = ret_value;
+               break;
+
+       default:
+
+               acpi_os_printf(" Unsupported return object type, %s",
+                              acpi_ut_get_type_name(ret_value->type));
+
+               acpi_os_free(return_obj.pointer);
+               return (AE_TYPE);
+       }
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_write_to_object
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              value               - Value to be written
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Performs a write to the specified object by invoking the
+ *              special debugger control method that writes the object. Thus,
+ *              the AML interpreter is doing all of the work, increasing the
+ *              validity of the test.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_write_to_object(struct acpi_namespace_node *node,
+                       union acpi_object *value)
+{
+       struct acpi_object_list param_objects;
+       union acpi_object params[2];
+       acpi_status status;
+
+       params[0].type = ACPI_TYPE_LOCAL_REFERENCE;
+       params[0].reference.actual_type = node->type;
+       params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node);
+
+       /* Copy the incoming user parameter */
+
+       memcpy(&params[1], value, sizeof(union acpi_object));
+
+       param_objects.count = 2;
+       param_objects.pointer = params;
+
+       acpi_gbl_method_executing = TRUE;
+       status = acpi_evaluate_object(write_handle, NULL, &param_objects, NULL);
+       acpi_gbl_method_executing = FALSE;
+
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not write to object, %s",
+                              acpi_format_exception(status));
+       }
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_evaluate_all_predefined_names
+ *
+ * PARAMETERS:  count_arg           - Max number of methods to execute
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Namespace batch execution. Execute predefined names in the
+ *              namespace, up to the max count, if specified.
+ *
+ ******************************************************************************/
+
+static void acpi_db_evaluate_all_predefined_names(char *count_arg)
+{
+       struct acpi_db_execute_walk info;
+
+       info.count = 0;
+       info.max_count = ACPI_UINT32_MAX;
+
+       if (count_arg) {
+               info.max_count = strtoul(count_arg, NULL, 0);
+       }
+
+       /* Search all nodes in namespace */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+                                 ACPI_UINT32_MAX,
+                                 acpi_db_evaluate_one_predefined_name, NULL,
+                                 (void *)&info, NULL);
+
+       acpi_os_printf("Evaluated %u predefined names in the namespace\n",
+                      info.count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_evaluate_one_predefined_name
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Batch execution module. Currently only executes predefined
+ *              ACPI names.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle,
+                                    u32 nesting_level,
+                                    void *context, void **return_value)
+{
+       struct acpi_namespace_node *node =
+           (struct acpi_namespace_node *)obj_handle;
+       struct acpi_db_execute_walk *info =
+           (struct acpi_db_execute_walk *)context;
+       char *pathname;
+       const union acpi_predefined_info *predefined;
+       struct acpi_device_info *obj_info;
+       struct acpi_object_list param_objects;
+       union acpi_object params[ACPI_METHOD_NUM_ARGS];
+       union acpi_object *this_param;
+       struct acpi_buffer return_obj;
+       acpi_status status;
+       u16 arg_type_list;
+       u8 arg_count;
+       u8 arg_type;
+       u32 i;
+
+       /* The name must be a predefined ACPI name */
+
+       predefined = acpi_ut_match_predefined_method(node->name.ascii);
+       if (!predefined) {
+               return (AE_OK);
+       }
+
+       if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
+               return (AE_OK);
+       }
+
+       pathname = acpi_ns_get_external_pathname(node);
+       if (!pathname) {
+               return (AE_OK);
+       }
+
+       /* Get the object info for number of method parameters */
+
+       status = acpi_get_object_info(obj_handle, &obj_info);
+       if (ACPI_FAILURE(status)) {
+               ACPI_FREE(pathname);
+               return (status);
+       }
+
+       param_objects.count = 0;
+       param_objects.pointer = NULL;
+
+       if (obj_info->type == ACPI_TYPE_METHOD) {
+
+               /* Setup default parameters (with proper types) */
+
+               arg_type_list = predefined->info.argument_list;
+               arg_count = METHOD_GET_ARG_COUNT(arg_type_list);
+
+               /*
+                * Setup the ACPI-required number of arguments, regardless of what
+                * the actual method defines. If there is a difference, then the
+                * method is wrong and a warning will be issued during execution.
+                */
+               this_param = params;
+               for (i = 0; i < arg_count; i++) {
+                       arg_type = METHOD_GET_NEXT_TYPE(arg_type_list);
+                       this_param->type = arg_type;
+
+                       switch (arg_type) {
+                       case ACPI_TYPE_INTEGER:
+
+                               this_param->integer.value = 1;
+                               break;
+
+                       case ACPI_TYPE_STRING:
+
+                               this_param->string.pointer =
+                                   "This is the default argument string";
+                               this_param->string.length =
+                                   strlen(this_param->string.pointer);
+                               break;
+
+                       case ACPI_TYPE_BUFFER:
+
+                               this_param->buffer.pointer = (u8 *)params;      /* just a garbage buffer */
+                               this_param->buffer.length = 48;
+                               break;
+
+                       case ACPI_TYPE_PACKAGE:
+
+                               this_param->package.elements = NULL;
+                               this_param->package.count = 0;
+                               break;
+
+                       default:
+
+                               acpi_os_printf
+                                   ("%s: Unsupported argument type: %u\n",
+                                    pathname, arg_type);
+                               break;
+                       }
+
+                       this_param++;
+               }
+
+               param_objects.count = arg_count;
+               param_objects.pointer = params;
+       }
+
+       ACPI_FREE(obj_info);
+       return_obj.pointer = NULL;
+       return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+       /* Do the actual method execution */
+
+       acpi_gbl_method_executing = TRUE;
+
+       status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
+
+       acpi_os_printf("%-32s returned %s\n",
+                      pathname, acpi_format_exception(status));
+       acpi_gbl_method_executing = FALSE;
+       ACPI_FREE(pathname);
+
+       /* Ignore status from method execution */
+
+       status = AE_OK;
+
+       /* Update count, check if we have executed enough methods */
+
+       info->count++;
+       if (info->count >= info->max_count) {
+               status = AE_CTRL_TERMINATE;
+       }
+
+       return (status);
+}
diff --git a/drivers/acpi/acpica/dbutils.c b/drivers/acpi/acpica/dbutils.c
new file mode 100644 (file)
index 0000000..86790e0
--- /dev/null
@@ -0,0 +1,457 @@
+/*******************************************************************************
+ *
+ * Module Name: dbutils - AML debugger utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbutils")
+
+/* Local prototypes */
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root);
+
+void acpi_db_dump_buffer(u32 address);
+#endif
+
+static char *gbl_hex_to_ascii = "0123456789ABCDEF";
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_argument
+ *
+ * PARAMETERS:  user_argument           - User command line
+ *              arguments               - Array of commands to match against
+ *
+ * RETURN:      Index into command array or ACPI_TYPE_NOT_FOUND if not found
+ *
+ * DESCRIPTION: Search command array for a command match
+ *
+ ******************************************************************************/
+
+acpi_object_type
+acpi_db_match_argument(char *user_argument,
+                      struct acpi_db_argument_info *arguments)
+{
+       u32 i;
+
+       if (!user_argument || user_argument[0] == 0) {
+               return (ACPI_TYPE_NOT_FOUND);
+       }
+
+       for (i = 0; arguments[i].name; i++) {
+               if (strstr(arguments[i].name, user_argument) ==
+                   arguments[i].name) {
+                       return (i);
+               }
+       }
+
+       /* Argument not recognized */
+
+       return (ACPI_TYPE_NOT_FOUND);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_output_destination
+ *
+ * PARAMETERS:  output_flags        - Current flags word
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set the current destination for debugger output. Also sets
+ *              the debug output level accordingly.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_output_destination(u32 output_flags)
+{
+
+       acpi_gbl_db_output_flags = (u8)output_flags;
+
+       if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) &&
+           acpi_gbl_db_output_to_file) {
+               acpi_dbg_level = acpi_gbl_db_debug_level;
+       } else {
+               acpi_dbg_level = acpi_gbl_db_console_debug_level;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_external_object
+ *
+ * PARAMETERS:  obj_desc        - External ACPI object to dump
+ *              level           - Nesting level.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump the contents of an ACPI external object
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level)
+{
+       u32 i;
+
+       if (!obj_desc) {
+               acpi_os_printf("[Null Object]\n");
+               return;
+       }
+
+       for (i = 0; i < level; i++) {
+               acpi_os_printf(" ");
+       }
+
+       switch (obj_desc->type) {
+       case ACPI_TYPE_ANY:
+
+               acpi_os_printf("[Null Object] (Type=0)\n");
+               break;
+
+       case ACPI_TYPE_INTEGER:
+
+               acpi_os_printf("[Integer] = %8.8X%8.8X\n",
+                              ACPI_FORMAT_UINT64(obj_desc->integer.value));
+               break;
+
+       case ACPI_TYPE_STRING:
+
+               acpi_os_printf("[String] Length %.2X = ",
+                              obj_desc->string.length);
+               acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX);
+               acpi_os_printf("\n");
+               break;
+
+       case ACPI_TYPE_BUFFER:
+
+               acpi_os_printf("[Buffer] Length %.2X = ",
+                              obj_desc->buffer.length);
+               if (obj_desc->buffer.length) {
+                       if (obj_desc->buffer.length > 16) {
+                               acpi_os_printf("\n");
+                       }
+                       acpi_ut_debug_dump_buffer(ACPI_CAST_PTR
+                                                 (u8,
+                                                  obj_desc->buffer.pointer),
+                                                 obj_desc->buffer.length,
+                                                 DB_BYTE_DISPLAY, _COMPONENT);
+               } else {
+                       acpi_os_printf("\n");
+               }
+               break;
+
+       case ACPI_TYPE_PACKAGE:
+
+               acpi_os_printf("[Package] Contains %u Elements:\n",
+                              obj_desc->package.count);
+
+               for (i = 0; i < obj_desc->package.count; i++) {
+                       acpi_db_dump_external_object(&obj_desc->package.
+                                                    elements[i], level + 1);
+               }
+               break;
+
+       case ACPI_TYPE_LOCAL_REFERENCE:
+
+               acpi_os_printf("[Object Reference] = ");
+               acpi_db_display_internal_object(obj_desc->reference.handle,
+                                               NULL);
+               break;
+
+       case ACPI_TYPE_PROCESSOR:
+
+               acpi_os_printf("[Processor]\n");
+               break;
+
+       case ACPI_TYPE_POWER:
+
+               acpi_os_printf("[Power Resource]\n");
+               break;
+
+       default:
+
+               acpi_os_printf("[Unknown Type] %X\n", obj_desc->type);
+               break;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_prep_namestring
+ *
+ * PARAMETERS:  name            - String to prepare
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Translate all forward slashes and dots to backslashes.
+ *
+ ******************************************************************************/
+
+void acpi_db_prep_namestring(char *name)
+{
+
+       if (!name) {
+               return;
+       }
+
+       acpi_ut_strupr(name);
+
+       /* Convert a leading forward slash to a backslash */
+
+       if (*name == '/') {
+               *name = '\\';
+       }
+
+       /* Ignore a leading backslash, this is the root prefix */
+
+       if (ACPI_IS_ROOT_PREFIX(*name)) {
+               name++;
+       }
+
+       /* Convert all slash path separators to dots */
+
+       while (*name) {
+               if ((*name == '/') || (*name == '\\')) {
+                       *name = '.';
+               }
+
+               name++;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_local_ns_lookup
+ *
+ * PARAMETERS:  name            - Name to lookup
+ *
+ * RETURN:      Pointer to a namespace node, null on failure
+ *
+ * DESCRIPTION: Lookup a name in the ACPI namespace
+ *
+ * Note: Currently begins search from the root. Could be enhanced to use
+ * the current prefix (scope) node as the search beginning point.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name)
+{
+       char *internal_path;
+       acpi_status status;
+       struct acpi_namespace_node *node = NULL;
+
+       acpi_db_prep_namestring(name);
+
+       /* Build an internal namestring */
+
+       status = acpi_ns_internalize_name(name, &internal_path);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Invalid namestring: %s\n", name);
+               return (NULL);
+       }
+
+       /*
+        * Lookup the name.
+        * (Uses root node as the search starting point)
+        */
+       status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY,
+                               ACPI_IMODE_EXECUTE,
+                               ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE,
+                               NULL, &node);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not locate name: %s, %s\n",
+                              name, acpi_format_exception(status));
+       }
+
+       ACPI_FREE(internal_path);
+       return (node);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_uint32_to_hex_string
+ *
+ * PARAMETERS:  value           - The value to be converted to string
+ *              buffer          - Buffer for result (not less than 11 bytes)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Convert the unsigned 32-bit value to the hexadecimal image
+ *
+ * NOTE: It is the caller's responsibility to ensure that the length of buffer
+ *       is sufficient.
+ *
+ ******************************************************************************/
+
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer)
+{
+       int i;
+
+       if (value == 0) {
+               strcpy(buffer, "0");
+               return;
+       }
+
+       buffer[8] = '\0';
+
+       for (i = 7; i >= 0; i--) {
+               buffer[i] = gbl_hex_to_ascii[value & 0x0F];
+               value = value >> 4;
+       }
+}
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_second_pass_parse
+ *
+ * PARAMETERS:  root            - Root of the parse tree
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until
+ *              second pass to parse the control methods
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root)
+{
+       union acpi_parse_object *op = root;
+       union acpi_parse_object *method;
+       union acpi_parse_object *search_op;
+       union acpi_parse_object *start_op;
+       acpi_status status = AE_OK;
+       u32 base_aml_offset;
+       struct acpi_walk_state *walk_state;
+
+       ACPI_FUNCTION_ENTRY();
+
+       acpi_os_printf("Pass two parse ....\n");
+
+       while (op) {
+               if (op->common.aml_opcode == AML_METHOD_OP) {
+                       method = op;
+
+                       /* Create a new walk state for the parse */
+
+                       walk_state =
+                           acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+                       if (!walk_state) {
+                               return (AE_NO_MEMORY);
+                       }
+
+                       /* Init the Walk State */
+
+                       walk_state->parser_state.aml =
+                           walk_state->parser_state.aml_start =
+                           method->named.data;
+                       walk_state->parser_state.aml_end =
+                           walk_state->parser_state.pkg_end =
+                           method->named.data + method->named.length;
+                       walk_state->parser_state.start_scope = op;
+
+                       walk_state->descending_callback =
+                           acpi_ds_load1_begin_op;
+                       walk_state->ascending_callback = acpi_ds_load1_end_op;
+
+                       /* Perform the AML parse */
+
+                       status = acpi_ps_parse_aml(walk_state);
+
+                       base_aml_offset =
+                           (method->common.value.arg)->common.aml_offset + 1;
+                       start_op = (method->common.value.arg)->common.next;
+                       search_op = start_op;
+
+                       while (search_op) {
+                               search_op->common.aml_offset += base_aml_offset;
+                               search_op =
+                                   acpi_ps_get_depth_next(start_op, search_op);
+                       }
+               }
+
+               if (op->common.aml_opcode == AML_REGION_OP) {
+
+                       /* TBD: [Investigate] this isn't quite the right thing to do! */
+                       /*
+                        *
+                        * Method = (ACPI_DEFERRED_OP *) Op;
+                        * Status = acpi_ps_parse_aml (Op, Method->Body, Method->body_length);
+                        */
+               }
+
+               if (ACPI_FAILURE(status)) {
+                       break;
+               }
+
+               op = acpi_ps_get_depth_next(root, op);
+       }
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_buffer
+ *
+ * PARAMETERS:  address             - Pointer to the buffer
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print a portion of a buffer
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_buffer(u32 address)
+{
+
+       acpi_os_printf("\nLocation %X:\n", address);
+
+       acpi_dbg_level |= ACPI_LV_TABLES;
+       acpi_ut_debug_dump_buffer(ACPI_TO_POINTER(address), 64, DB_BYTE_DISPLAY,
+                                 ACPI_UINT32_MAX);
+}
+#endif
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
new file mode 100644 (file)
index 0000000..342298a
--- /dev/null
@@ -0,0 +1,513 @@
+/*******************************************************************************
+ *
+ * Module Name: dbxface - AML Debugger external interfaces
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbxface")
+
+/* Local prototypes */
+static acpi_status
+acpi_db_start_command(struct acpi_walk_state *walk_state,
+                     union acpi_parse_object *op);
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+void acpi_db_method_end(struct acpi_walk_state *walk_state);
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_start_command
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing Op, from AML interpreter
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enter debugger command loop
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_start_command(struct acpi_walk_state *walk_state,
+                     union acpi_parse_object *op)
+{
+       acpi_status status;
+
+       /* TBD: [Investigate] are there namespace locking issues here? */
+
+       /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
+
+       /* Go into the command loop and await next user command */
+
+       acpi_gbl_method_executing = TRUE;
+       status = AE_CTRL_TRUE;
+       while (status == AE_CTRL_TRUE) {
+               if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) {
+
+                       /* Handshake with the front-end that gets user command lines */
+
+                       acpi_os_release_mutex(acpi_gbl_db_command_complete);
+
+                       status =
+                           acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
+                                                 ACPI_WAIT_FOREVER);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+               } else {
+                       /* Single threaded, we must get a command line ourselves */
+
+                       /* Force output to console until a command is entered */
+
+                       acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+
+                       /* Different prompt if method is executing */
+
+                       if (!acpi_gbl_method_executing) {
+                               acpi_os_printf("%1c ",
+                                              ACPI_DEBUGGER_COMMAND_PROMPT);
+                       } else {
+                               acpi_os_printf("%1c ",
+                                              ACPI_DEBUGGER_EXECUTE_PROMPT);
+                       }
+
+                       /* Get the user input line */
+
+                       status = acpi_os_get_line(acpi_gbl_db_line_buf,
+                                                 ACPI_DB_LINE_BUFFER_SIZE,
+                                                 NULL);
+                       if (ACPI_FAILURE(status)) {
+                               ACPI_EXCEPTION((AE_INFO, status,
+                                               "While parsing command line"));
+                               return (status);
+                       }
+               }
+
+               status =
+                   acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
+                                            op);
+       }
+
+       /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_single_step
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing op (from aml interpreter)
+ *              opcode_class    - Class of the current AML Opcode
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Called just before execution of an AML opcode.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_single_step(struct acpi_walk_state * walk_state,
+                   union acpi_parse_object * op, u32 opcode_class)
+{
+       union acpi_parse_object *next;
+       acpi_status status = AE_OK;
+       u32 original_debug_level;
+       union acpi_parse_object *display_op;
+       union acpi_parse_object *parent_op;
+       u32 aml_offset;
+
+       ACPI_FUNCTION_ENTRY();
+
+#ifndef ACPI_APPLICATION
+       if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
+               return (AE_OK);
+       }
+#endif
+
+       /* Check the abort flag */
+
+       if (acpi_gbl_abort_method) {
+               acpi_gbl_abort_method = FALSE;
+               return (AE_ABORT_METHOD);
+       }
+
+       aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
+                                       walk_state->parser_state.aml_start);
+
+       /* Check for single-step breakpoint */
+
+       if (walk_state->method_breakpoint &&
+           (walk_state->method_breakpoint <= aml_offset)) {
+
+               /* Check if the breakpoint has been reached or passed */
+               /* Hit the breakpoint, resume single step, reset breakpoint */
+
+               acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
+               acpi_gbl_cm_single_step = TRUE;
+               acpi_gbl_step_to_next_call = FALSE;
+               walk_state->method_breakpoint = 0;
+       }
+
+       /* Check for user breakpoint (Must be on exact Aml offset) */
+
+       else if (walk_state->user_breakpoint &&
+                (walk_state->user_breakpoint == aml_offset)) {
+               acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
+                              aml_offset);
+               acpi_gbl_cm_single_step = TRUE;
+               acpi_gbl_step_to_next_call = FALSE;
+               walk_state->method_breakpoint = 0;
+       }
+
+       /*
+        * Check if this is an opcode that we are interested in --
+        * namely, opcodes that have arguments
+        */
+       if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+               return (AE_OK);
+       }
+
+       switch (opcode_class) {
+       case AML_CLASS_UNKNOWN:
+       case AML_CLASS_ARGUMENT:        /* constants, literals, etc. do nothing */
+
+               return (AE_OK);
+
+       default:
+
+               /* All other opcodes -- continue */
+               break;
+       }
+
+       /*
+        * Under certain debug conditions, display this opcode and its operands
+        */
+       if ((acpi_gbl_db_output_to_file) ||
+           (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
+               if ((acpi_gbl_db_output_to_file) ||
+                   (acpi_dbg_level & ACPI_LV_PARSE)) {
+                       acpi_os_printf
+                           ("\n[AmlDebug] Next AML Opcode to execute:\n");
+               }
+
+               /*
+                * Display this op (and only this op - zero out the NEXT field
+                * temporarily, and disable parser trace output for the duration of
+                * the display because we don't want the extraneous debug output)
+                */
+               original_debug_level = acpi_dbg_level;
+               acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
+               next = op->common.next;
+               op->common.next = NULL;
+
+               display_op = op;
+               parent_op = op->common.parent;
+               if (parent_op) {
+                       if ((walk_state->control_state) &&
+                           (walk_state->control_state->common.state ==
+                            ACPI_CONTROL_PREDICATE_EXECUTING)) {
+                               /*
+                                * We are executing the predicate of an IF or WHILE statement
+                                * Search upwards for the containing IF or WHILE so that the
+                                * entire predicate can be displayed.
+                                */
+                               while (parent_op) {
+                                       if ((parent_op->common.aml_opcode ==
+                                            AML_IF_OP)
+                                           || (parent_op->common.aml_opcode ==
+                                               AML_WHILE_OP)) {
+                                               display_op = parent_op;
+                                               break;
+                                       }
+                                       parent_op = parent_op->common.parent;
+                               }
+                       } else {
+                               while (parent_op) {
+                                       if ((parent_op->common.aml_opcode ==
+                                            AML_IF_OP)
+                                           || (parent_op->common.aml_opcode ==
+                                               AML_ELSE_OP)
+                                           || (parent_op->common.aml_opcode ==
+                                               AML_SCOPE_OP)
+                                           || (parent_op->common.aml_opcode ==
+                                               AML_METHOD_OP)
+                                           || (parent_op->common.aml_opcode ==
+                                               AML_WHILE_OP)) {
+                                               break;
+                                       }
+                                       display_op = parent_op;
+                                       parent_op = parent_op->common.parent;
+                               }
+                       }
+               }
+
+               /* Now we can display it */
+
+#ifdef ACPI_DISASSEMBLER
+               acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
+#endif
+
+               if ((op->common.aml_opcode == AML_IF_OP) ||
+                   (op->common.aml_opcode == AML_WHILE_OP)) {
+                       if (walk_state->control_state->common.value) {
+                               acpi_os_printf
+                                   ("Predicate = [True], IF block was executed\n");
+                       } else {
+                               acpi_os_printf
+                                   ("Predicate = [False], Skipping IF block\n");
+                       }
+               } else if (op->common.aml_opcode == AML_ELSE_OP) {
+                       acpi_os_printf
+                           ("Predicate = [False], ELSE block was executed\n");
+               }
+
+               /* Restore everything */
+
+               op->common.next = next;
+               acpi_os_printf("\n");
+               if ((acpi_gbl_db_output_to_file) ||
+                   (acpi_dbg_level & ACPI_LV_PARSE)) {
+                       acpi_os_printf("\n");
+               }
+               acpi_dbg_level = original_debug_level;
+       }
+
+       /* If we are not single stepping, just continue executing the method */
+
+       if (!acpi_gbl_cm_single_step) {
+               return (AE_OK);
+       }
+
+       /*
+        * If we are executing a step-to-call command,
+        * Check if this is a method call.
+        */
+       if (acpi_gbl_step_to_next_call) {
+               if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
+
+                       /* Not a method call, just keep executing */
+
+                       return (AE_OK);
+               }
+
+               /* Found a method call, stop executing */
+
+               acpi_gbl_step_to_next_call = FALSE;
+       }
+
+       /*
+        * If the next opcode is a method call, we will "step over" it
+        * by default.
+        */
+       if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
+
+               /* Force no more single stepping while executing called method */
+
+               acpi_gbl_cm_single_step = FALSE;
+
+               /*
+                * Set the breakpoint on/before the call, it will stop execution
+                * as soon as we return
+                */
+               walk_state->method_breakpoint = 1;      /* Must be non-zero! */
+       }
+
+       status = acpi_db_start_command(walk_state, op);
+
+       /* User commands complete, continue execution of the interrupted method */
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_initialize_debugger
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Init and start debugger
+ *
+ ******************************************************************************/
+
+acpi_status acpi_initialize_debugger(void)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
+
+       /* Init globals */
+
+       acpi_gbl_db_buffer = NULL;
+       acpi_gbl_db_filename = NULL;
+       acpi_gbl_db_output_to_file = FALSE;
+
+       acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
+       acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
+       acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
+
+       acpi_gbl_db_opt_no_ini_methods = FALSE;
+
+       acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
+       if (!acpi_gbl_db_buffer) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+       memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
+
+       /* Initial scope is the root */
+
+       acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
+       acpi_gbl_db_scope_buf[1] = 0;
+       acpi_gbl_db_scope_node = acpi_gbl_root_node;
+
+       /* Initialize user commands loop */
+
+       acpi_gbl_db_terminate_loop = FALSE;
+
+       /*
+        * If configured for multi-thread support, the debug executor runs in
+        * a separate thread so that the front end can be in another address
+        * space, environment, or even another machine.
+        */
+       if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
+
+               /* These were created with one unit, grab it */
+
+               status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
+                                              ACPI_WAIT_FOREVER);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not get debugger mutex\n");
+                       return_ACPI_STATUS(status);
+               }
+
+               status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
+                                              ACPI_WAIT_FOREVER);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Could not get debugger mutex\n");
+                       return_ACPI_STATUS(status);
+               }
+
+               /* Create the debug execution thread to execute commands */
+
+               acpi_gbl_db_threads_terminated = FALSE;
+               status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
+                                        acpi_db_execute_thread, NULL);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "Could not start debugger thread"));
+                       acpi_gbl_db_threads_terminated = TRUE;
+                       return_ACPI_STATUS(status);
+               }
+       } else {
+               acpi_gbl_db_thread_id = acpi_os_get_thread_id();
+       }
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_terminate_debugger
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Stop debugger
+ *
+ ******************************************************************************/
+void acpi_terminate_debugger(void)
+{
+
+       /* Terminate the AML Debugger */
+
+       acpi_gbl_db_terminate_loop = TRUE;
+
+       if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
+               acpi_os_release_mutex(acpi_gbl_db_command_ready);
+
+               /* Wait the AML Debugger threads */
+
+               while (!acpi_gbl_db_threads_terminated) {
+                       acpi_os_sleep(100);
+               }
+       }
+
+       if (acpi_gbl_db_buffer) {
+               acpi_os_free(acpi_gbl_db_buffer);
+               acpi_gbl_db_buffer = NULL;
+       }
+
+       /* Ensure that debug output is now disabled */
+
+       acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_debugger_thread_id
+ *
+ * PARAMETERS:  thread_id       - Debugger thread ID
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set debugger thread ID
+ *
+ ******************************************************************************/
+void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
+{
+       acpi_gbl_db_thread_id = thread_id;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)
index 81f2d9e87fad518369acc5eaca9d99172f22fdf5..07d22bfbaa00d99f8f549d0deb94cd688122177e 100644 (file)
@@ -405,7 +405,7 @@ cleanup:
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
-#endif                         /*  ACPI_FUTURE_USAGE  */
+#endif
 
 #if (!ACPI_REDUCED_HARDWARE)
 /*******************************************************************************
index 075d654c837f27e767ebed874e68140b97fc12ff..1e4c5b6dc0b0ed400056cf59097875bf8a99ccfd 100644 (file)
@@ -618,6 +618,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
                break;
 
        case ARGI_TARGETREF:
+       case ARGI_STORE_TARGET:
 
                switch (destination_type) {
                case ACPI_TYPE_INTEGER:
index 7b109128b0350f0579fdf0b96fe0c74f949887b0..a1afe1a1e7c2cada36b9a6763bd81f3efa205dfa 100644 (file)
@@ -209,7 +209,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
                                         * (i.e., dereference the package index)
                                         * Delete the ref object, increment the returned object
                                         */
-                                       acpi_ut_remove_reference(stack_desc);
                                        acpi_ut_add_reference(obj_desc);
                                        *stack_ptr = obj_desc;
                                } else {
index d2964af9ad4df52e9846c02a7e129e7d0f8c0ea2..424442d50b5e474c4a40eed1cb531af2aeede393 100644 (file)
@@ -307,6 +307,8 @@ acpi_ex_resolve_operands(u16 opcode,
                case ARGI_TARGETREF:    /* Allows implicit conversion rules before store */
                case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
                case ARGI_SIMPLE_TARGET:        /* Name, Local, or arg - no implicit conversion  */
+               case ARGI_STORE_TARGET:
+
                        /*
                         * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
                         * A Namespace Node is OK as-is
index a7eee2400ce01a592bcbe736745a6d3f0e6190f4..c076e9100d66823d332e382ab05c7b694f56b82e 100644 (file)
@@ -137,7 +137,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
                /* Destination is not a Reference object */
 
                ACPI_ERROR((AE_INFO,
-                           "Target is not a Reference or Constant object - %s [%p]",
+                           "Target is not a Reference or Constant object - [%s] %p",
                            acpi_ut_get_object_type_name(dest_desc),
                            dest_desc));
 
@@ -189,7 +189,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
                 * displayed and otherwise has no effect -- see ACPI Specification
                 */
                ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "**** Write to Debug Object: Object %p %s ****:\n\n",
+                                 "**** Write to Debug Object: Object %p [%s] ****:\n\n",
                                  source_desc,
                                  acpi_ut_get_object_type_name(source_desc)));
 
@@ -341,7 +341,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
                        /* All other types are invalid */
 
                        ACPI_ERROR((AE_INFO,
-                                   "Source must be Integer/Buffer/String type, not %s",
+                                   "Source must be type [Integer/Buffer/String], found [%s]",
                                    acpi_ut_get_object_type_name(source_desc)));
                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
                }
@@ -352,8 +352,9 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
                break;
 
        default:
-               ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField"));
-               status = AE_AML_OPERAND_TYPE;
+               ACPI_ERROR((AE_INFO,
+                           "Target is not of type [Package/BufferField]"));
+               status = AE_AML_TARGET_TYPE;
                break;
        }
 
@@ -373,20 +374,20 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
  *
  * DESCRIPTION: Store the object to the named object.
  *
- *              The Assignment of an object to a named object is handled here
- *              The value passed in will replace the current value (if any)
- *              with the input value.
+ * The assignment of an object to a named object is handled here.
+ * The value passed in will replace the current value (if any)
+ * with the input value.
  *
- *              When storing into an object the data is converted to the
- *              target object type then stored in the object. This means
- *              that the target object type (for an initialized target) will
- *              not be changed by a store operation. A copy_object can change
- *              the target type, however.
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation. A copy_object can change
+ * the target type, however.
  *
- *              The implicit_conversion flag is set to NO/FALSE only when
- *              storing to an arg_x -- as per the rules of the ACPI spec.
+ * The implicit_conversion flag is set to NO/FALSE only when
+ * storing to an arg_x -- as per the rules of the ACPI spec.
  *
- *              Assumes parameters are already validated.
+ * Assumes parameters are already validated.
  *
  ******************************************************************************/
 
@@ -408,11 +409,75 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
        target_type = acpi_ns_get_type(node);
        target_desc = acpi_ns_get_attached_object(node);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n",
                          source_desc,
                          acpi_ut_get_object_type_name(source_desc), node,
                          acpi_ut_get_type_name(target_type)));
 
+       /* Only limited target types possible for everything except copy_object */
+
+       if (walk_state->opcode != AML_COPY_OP) {
+               /*
+                * Only copy_object allows all object types to be overwritten. For
+                * target_ref(s), there are restrictions on the object types that
+                * are allowed.
+                *
+                * Allowable operations/typing for Store:
+                *
+                * 1) Simple Store
+                *      Integer     --> Integer (Named/Local/Arg)
+                *      String      --> String  (Named/Local/Arg)
+                *      Buffer      --> Buffer  (Named/Local/Arg)
+                *      Package     --> Package (Named/Local/Arg)
+                *
+                * 2) Store with implicit conversion
+                *      Integer     --> String or Buffer  (Named)
+                *      String      --> Integer or Buffer (Named)
+                *      Buffer      --> Integer or String (Named)
+                */
+               switch (target_type) {
+               case ACPI_TYPE_PACKAGE:
+                       /*
+                        * Here, can only store a package to an existing package.
+                        * Storing a package to a Local/Arg is OK, and handled
+                        * elsewhere.
+                        */
+                       if (walk_state->opcode == AML_STORE_OP) {
+                               if (source_desc->common.type !=
+                                   ACPI_TYPE_PACKAGE) {
+                                       ACPI_ERROR((AE_INFO,
+                                                   "Cannot assign type [%s] to [Package] "
+                                                   "(source must be type Pkg)",
+                                                   acpi_ut_get_object_type_name
+                                                   (source_desc)));
+
+                                       return_ACPI_STATUS(AE_AML_TARGET_TYPE);
+                               }
+                               break;
+                       }
+
+                       /* Fallthrough */
+
+               case ACPI_TYPE_DEVICE:
+               case ACPI_TYPE_EVENT:
+               case ACPI_TYPE_MUTEX:
+               case ACPI_TYPE_REGION:
+               case ACPI_TYPE_POWER:
+               case ACPI_TYPE_PROCESSOR:
+               case ACPI_TYPE_THERMAL:
+
+                       ACPI_ERROR((AE_INFO,
+                                   "Target must be [Buffer/Integer/String/Reference], found [%s] (%4.4s)",
+                                   acpi_ut_get_type_name(node->type),
+                                   node->name.ascii));
+
+                       return_ACPI_STATUS(AE_AML_TARGET_TYPE);
+
+               default:
+                       break;
+               }
+       }
+
        /*
         * Resolve the source object to an actual value
         * (If it is a reference object)
@@ -425,13 +490,13 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
        /* Do the actual store operation */
 
        switch (target_type) {
-       case ACPI_TYPE_INTEGER:
-       case ACPI_TYPE_STRING:
-       case ACPI_TYPE_BUFFER:
                /*
                 * The simple data types all support implicit source operand
                 * conversion before the store.
                 */
+       case ACPI_TYPE_INTEGER:
+       case ACPI_TYPE_STRING:
+       case ACPI_TYPE_BUFFER:
 
                if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) {
                        /*
@@ -467,7 +532,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
                                                       new_desc->common.type);
 
                        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                         "Store %s into %s via Convert/Attach\n",
+                                         "Store type [%s] into [%s] via Convert/Attach\n",
                                          acpi_ut_get_object_type_name
                                          (source_desc),
                                          acpi_ut_get_object_type_name
@@ -491,15 +556,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 
        default:
                /*
-                * No conversions for all other types. Directly store a copy of
-                * the source object. This is the ACPI spec-defined behavior for
-                * the copy_object operator.
+                * copy_object operator: No conversions for all other types.
+                * Instead, directly store a copy of the source object.
                 *
-                * NOTE: For the Store operator, this is a departure from the
-                * ACPI spec, which states "If conversion is impossible, abort
-                * the running control method". Instead, this code implements
-                * "If conversion is impossible, treat the Store operation as
-                * a CopyObject".
+                * This is the ACPI spec-defined behavior for the copy_object
+                * operator. (Note, for this default case, all normal
+                * Store/Target operations exited above with an error).
                 */
                status = acpi_ex_store_direct_to_node(source_desc, node,
                                                      walk_state);
index 3101607b4efeaa5721e1cd62752ff27d576e928c..d1841defa6690c053aa7e283fbf29af526a04846 100644 (file)
@@ -122,9 +122,10 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
                        /* Conversion successful but still not a valid type */
 
                        ACPI_ERROR((AE_INFO,
-                                   "Cannot assign type %s to %s (must be type Int/Str/Buf)",
+                                   "Cannot assign type [%s] to [%s] (must be type Int/Str/Buf)",
                                    acpi_ut_get_object_type_name(source_desc),
                                    acpi_ut_get_type_name(target_type)));
+
                        status = AE_AML_OPERAND_TYPE;
                }
                break;
@@ -275,7 +276,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
                /*
                 * All other types come here.
                 */
-               ACPI_WARNING((AE_INFO, "Store into type %s not implemented",
+               ACPI_WARNING((AE_INFO, "Store into type [%s] not implemented",
                              acpi_ut_get_object_type_name(dest_desc)));
 
                status = AE_NOT_IMPLEMENTED;
index 0f1daba640e7a5f70c5a6f0196398f65551219d8..37aa5c45ca4b1936dbf18a00a4c40537505c3e2f 100644 (file)
@@ -60,7 +60,6 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
 
 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
-#ifdef ACPI_FUTURE_USAGE
 static acpi_status
 acpi_ns_dump_one_object_path(acpi_handle obj_handle,
                             u32 level, void *context, void **return_value);
@@ -68,7 +67,6 @@ acpi_ns_dump_one_object_path(acpi_handle obj_handle,
 static acpi_status
 acpi_ns_get_max_depth(acpi_handle obj_handle,
                      u32 level, void *context, void **return_value);
-#endif                         /* ACPI_FUTURE_USAGE */
 
 /*******************************************************************************
  *
@@ -625,7 +623,6 @@ cleanup:
        return (AE_OK);
 }
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_objects
@@ -680,9 +677,7 @@ acpi_ns_dump_objects(acpi_object_type type,
 
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
-#endif                         /* ACPI_FUTURE_USAGE */
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_one_object_path, acpi_ns_get_max_depth
@@ -810,7 +805,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
 
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
-#endif                         /* ACPI_FUTURE_USAGE */
 
 /*******************************************************************************
  *
index 0eb54315b4bebbd131c5b4c9ae40909ea0ca61b7..0c20980bbcf3dd4a49be177b937dade77ebdb49a 100644 (file)
@@ -226,7 +226,7 @@ acpi_ns_check_object_type(struct acpi_evaluate_info *info,
 {
        union acpi_operand_object *return_object = *return_object_ptr;
        acpi_status status = AE_OK;
-       char type_buffer[48];   /* Room for 5 types */
+       char type_buffer[96];   /* Room for 10 types */
 
        /* A Namespace node should not get here, but make sure */
 
index 89984f30addca71dfe02080335daec6ea2c0067d..cf2f2faf4f92098cedf4b0583320743820b90f9e 100644 (file)
@@ -183,7 +183,6 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
        }
 }
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ps_get_depth_next
@@ -317,4 +316,3 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
        return (child);
 }
 #endif
-#endif                         /*  ACPI_FUTURE_USAGE  */
index 183cc1efbc5182d990dacaa88b5bff1471d2ee8b..71d2877cd2cefa9c1a98bcae4e3dbb686a20ffea 100644 (file)
@@ -205,7 +205,6 @@ u8 acpi_ps_is_leading_char(u32 c)
 /*
  * Get op's name (4-byte name segment) or 0 if unnamed
  */
-#ifdef ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object * op)
 {
 
@@ -219,7 +218,6 @@ u32 acpi_ps_get_name(union acpi_parse_object * op)
 
        return (op->named.name);
 }
-#endif                         /*  ACPI_FUTURE_USAGE  */
 
 /*
  * Set op's name
index c428bb33204ee89cd01fcb84d0e7e8e8e080a4dc..2a09288e7c57c3d1a6df3a0f93dc9a3b49ed24ac 100644 (file)
@@ -51,7 +51,6 @@ ACPI_MODULE_NAME("rsdump")
 /*
  * All functions in this module are used by the AML Debugger only
  */
-#if defined(ACPI_DEBUGGER)
 /* Local prototypes */
 static void acpi_rs_out_string(char *title, char *value);
 
@@ -565,5 +564,3 @@ static void acpi_rs_dump_word_list(u16 length, u16 *data)
                acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]);
        }
 }
-
-#endif
index 52b024df00524bffae3bb1117cffa0d3dc31eb3b..9486992edbb82b5c29094352b6d0eea536f7046d 100644 (file)
@@ -564,7 +564,6 @@ acpi_rs_get_crs_method_data(struct acpi_namespace_node *node,
  *
  ******************************************************************************/
 
-#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
                            struct acpi_buffer *ret_buffer)
@@ -596,7 +595,6 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
        acpi_ut_remove_reference(obj_desc);
        return_ACPI_STATUS(status);
 }
-#endif                         /*  ACPI_FUTURE_USAGE  */
 
 /*******************************************************************************
  *
index de51f836ef68e23280897bda0aca300b5341db90..1e8cd572332640fe5a6faa9db3a64f3ff0b56b07 100644 (file)
@@ -220,7 +220,7 @@ acpi_get_current_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_current_resources)
-#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_possible_resources
@@ -262,7 +262,7 @@ acpi_get_possible_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)
-#endif                         /*  ACPI_FUTURE_USAGE  */
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_set_current_resources
index 988e23b7795caaaa40f6a4320310f1d8c1026085..ecaaaffc078813a2429ce86470e3fbe7e0c5544c 100644 (file)
@@ -232,12 +232,27 @@ char *acpi_ut_get_type_name(acpi_object_type type)
 
 char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
 {
+       ACPI_FUNCTION_TRACE(ut_get_object_type_name);
 
        if (!obj_desc) {
-               return ("[NULL Object Descriptor]");
+               ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
+               return_PTR("[NULL Object Descriptor]");
        }
 
-       return (acpi_ut_get_type_name(obj_desc->common.type));
+       /* These descriptor types share a common area */
+
+       if ((ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) &&
+           (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_NAMED)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                                 "Invalid object descriptor type: 0x%2.2X [%s] (%p)\n",
+                                 ACPI_GET_DESCRIPTOR_TYPE(obj_desc),
+                                 acpi_ut_get_descriptor_name(obj_desc),
+                                 obj_desc));
+
+               return_PTR("Invalid object");
+       }
+
+       return_PTR(acpi_ut_get_type_name(obj_desc->common.type));
 }
 
 /*******************************************************************************
@@ -407,8 +422,6 @@ static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
        "ACPI_MTX_Events",
        "ACPI_MTX_Caches",
        "ACPI_MTX_Memory",
-       "ACPI_MTX_CommandComplete",
-       "ACPI_MTX_CommandReady"
 };
 
 char *acpi_ut_get_mutex_name(u32 mutex_id)
index 75a94f52b4bee07df7ac5722b64276bad82e42f4..d435b7b7eb948416db9e7d397e482c8ebd8e0743 100644 (file)
@@ -45,6 +45,7 @@
 #include "accommon.h"
 #include "actables.h"
 #include "acapps.h"
+#include "errno.h"
 
 #ifdef ACPI_ASL_COMPILER
 #include "aslcompiler.h"
@@ -301,6 +302,11 @@ acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table)
        file = fopen(filename, "rb");
        if (!file) {
                perror("Could not open input file");
+
+               if (errno == ENOENT) {
+                       return (AE_NOT_EXIST);
+               }
+
                return (status);
        }
 
index 28ab3a1d5ec1632b07b77b037869d4e7c815a167..ccd0745f011e886619dd2b891e51d23df372e08a 100644 (file)
@@ -241,8 +241,6 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_disable_mem_tracking = FALSE;
 #endif
 
-       ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE);
-
        return_ACPI_STATUS(AE_OK);
 }
 
@@ -284,6 +282,19 @@ void acpi_ut_subsystem_shutdown(void)
 {
        ACPI_FUNCTION_TRACE(ut_subsystem_shutdown);
 
+       /* Just exit if subsystem is already shutdown */
+
+       if (acpi_gbl_shutdown) {
+               ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
+               return_VOID;
+       }
+
+       /* Subsystem appears active, go ahead and shut it down */
+
+       acpi_gbl_shutdown = TRUE;
+       acpi_gbl_startup_flags = 0;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+
 #ifndef ACPI_ASL_COMPILER
 
        /* Close the acpi_event Handling */
index 37b8b58fcd565e563879f331be4cf983ae4c9f5f..ce406e39b669cd336b95b7b39c73dfa1c317b361 100644 (file)
@@ -108,6 +108,21 @@ acpi_status acpi_ut_mutex_initialize(void)
        /* Create the reader/writer lock for namespace access */
 
        status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+#ifdef ACPI_DEBUGGER
+
+       /* Debugger Support */
+
+       status = acpi_os_create_mutex(&acpi_gbl_db_command_ready);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       status = acpi_os_create_mutex(&acpi_gbl_db_command_complete);
+#endif
+
        return_ACPI_STATUS(status);
 }
 
@@ -147,6 +162,12 @@ void acpi_ut_mutex_terminate(void)
        /* Delete the reader/writer lock */
 
        acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock);
+
+#ifdef ACPI_DEBUGGER
+       acpi_os_delete_mutex(acpi_gbl_db_command_ready);
+       acpi_os_delete_mutex(acpi_gbl_db_command_complete);
+#endif
+
        return_VOID;
 }
 
index 4f332815db00c1356f2a3dd357d32349a92169ec..f9c8f9ce1f0f3e315d00db27e5e5623b92f278fa 100644 (file)
@@ -67,23 +67,6 @@ acpi_status __init acpi_terminate(void)
 
        ACPI_FUNCTION_TRACE(acpi_terminate);
 
-       /* Just exit if subsystem is already shutdown */
-
-       if (acpi_gbl_shutdown) {
-               ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Subsystem appears active, go ahead and shut it down */
-
-       acpi_gbl_shutdown = TRUE;
-       acpi_gbl_startup_flags = 0;
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
-
-       /* Terminate the AML Debugger if present */
-
-       ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE);
-
        /* Shutdown and free all resources */
 
        acpi_ut_subsystem_shutdown();
@@ -270,7 +253,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
-#endif                         /*  ACPI_FUTURE_USAGE  */
+#endif
 
 /*****************************************************************************
  *
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
new file mode 100644 (file)
index 0000000..3c083d2
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+ * CPPC (Collaborative Processor Performance Control) methods used by CPUfreq drivers.
+ *
+ * (C) Copyright 2014, 2015 Linaro Ltd.
+ * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * CPPC describes a few methods for controlling CPU performance using
+ * information from a per CPU table called CPC. This table is described in
+ * the ACPI v5.0+ specification. The table consists of a list of
+ * registers which may be memory mapped or hardware registers and also may
+ * include some static integer values.
+ *
+ * CPU performance is on an abstract continuous scale as against a discretized
+ * P-state scale which is tied to CPU frequency only. In brief, the basic
+ * operation involves:
+ *
+ * - OS makes a CPU performance request. (Can provide min and max bounds)
+ *
+ * - Platform (such as BMC) is free to optimize request within requested bounds
+ *   depending on power/thermal budgets etc.
+ *
+ * - Platform conveys its decision back to OS
+ *
+ * The communication between OS and platform occurs through another medium
+ * called (PCC) Platform Communication Channel. This is a generic mailbox like
+ * mechanism which includes doorbell semantics to indicate register updates.
+ * See drivers/mailbox/pcc.c for details on PCC.
+ *
+ * Finer details about the PCC and CPPC spec are available in the ACPI v5.1 and
+ * above specifications.
+ */
+
+#define pr_fmt(fmt)    "ACPI CPPC: " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+
+#include <acpi/cppc_acpi.h>
+/*
+ * Lock to provide mutually exclusive access to the PCC
+ * channel. e.g. When the remote updates the shared region
+ * with new data, the reader needs to be protected from
+ * other CPUs activity on the same channel.
+ */
+static DEFINE_SPINLOCK(pcc_lock);
+
+/*
+ * The cpc_desc structure contains the ACPI register details
+ * as described in the per CPU _CPC tables. The details
+ * include the type of register (e.g. PCC, System IO, FFH etc.)
+ * and destination addresses which lets us READ/WRITE CPU performance
+ * information using the appropriate I/O methods.
+ */
+static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
+
+/* This layer handles all the PCC specifics for CPPC. */
+static struct mbox_chan *pcc_channel;
+static void __iomem *pcc_comm_addr;
+static u64 comm_base_addr;
+static int pcc_subspace_idx = -1;
+static u16 pcc_cmd_delay;
+static bool pcc_channel_acquired;
+
+/*
+ * Arbitrary Retries in case the remote processor is slow to respond
+ * to PCC commands.
+ */
+#define NUM_RETRIES 500
+
+static int send_pcc_cmd(u16 cmd)
+{
+       int retries, result = -EIO;
+       struct acpi_pcct_hw_reduced *pcct_ss = pcc_channel->con_priv;
+       struct acpi_pcct_shared_memory *generic_comm_base =
+               (struct acpi_pcct_shared_memory *) pcc_comm_addr;
+       u32 cmd_latency = pcct_ss->latency;
+
+       /* Min time OS should wait before sending next command. */
+       udelay(pcc_cmd_delay);
+
+       /* Write to the shared comm region. */
+       writew(cmd, &generic_comm_base->command);
+
+       /* Flip CMD COMPLETE bit */
+       writew(0, &generic_comm_base->status);
+
+       /* Ring doorbell */
+       result = mbox_send_message(pcc_channel, &cmd);
+       if (result < 0) {
+               pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n",
+                               cmd, result);
+               return result;
+       }
+
+       /* Wait for a nominal time to let platform process command. */
+       udelay(cmd_latency);
+
+       /* Retry in case the remote processor was too slow to catch up. */
+       for (retries = NUM_RETRIES; retries > 0; retries--) {
+               if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) {
+                       result = 0;
+                       break;
+               }
+       }
+
+       mbox_client_txdone(pcc_channel, result);
+       return result;
+}
+
+static void cppc_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
+{
+       if (ret)
+               pr_debug("TX did not complete: CMD sent:%x, ret:%d\n",
+                               *(u16 *)msg, ret);
+       else
+               pr_debug("TX completed. CMD sent:%x, ret:%d\n",
+                               *(u16 *)msg, ret);
+}
+
+struct mbox_client cppc_mbox_cl = {
+       .tx_done = cppc_chan_tx_done,
+       .knows_txdone = true,
+};
+
+static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle)
+{
+       int result = -EFAULT;
+       acpi_status status = AE_OK;
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
+       struct acpi_buffer state = {0, NULL};
+       union acpi_object  *psd = NULL;
+       struct acpi_psd_package *pdomain;
+
+       status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer,
+                       ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       psd = buffer.pointer;
+       if (!psd || psd->package.count != 1) {
+               pr_debug("Invalid _PSD data\n");
+               goto end;
+       }
+
+       pdomain = &(cpc_ptr->domain_info);
+
+       state.length = sizeof(struct acpi_psd_package);
+       state.pointer = pdomain;
+
+       status = acpi_extract_package(&(psd->package.elements[0]),
+               &format, &state);
+       if (ACPI_FAILURE(status)) {
+               pr_debug("Invalid _PSD data for CPU:%d\n", cpc_ptr->cpu_id);
+               goto end;
+       }
+
+       if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
+               pr_debug("Unknown _PSD:num_entries for CPU:%d\n", cpc_ptr->cpu_id);
+               goto end;
+       }
+
+       if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
+               pr_debug("Unknown _PSD:revision for CPU: %d\n", cpc_ptr->cpu_id);
+               goto end;
+       }
+
+       if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
+           pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
+           pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
+               pr_debug("Invalid _PSD:coord_type for CPU:%d\n", cpc_ptr->cpu_id);
+               goto end;
+       }
+
+       result = 0;
+end:
+       kfree(buffer.pointer);
+       return result;
+}
+
+/**
+ * acpi_get_psd_map - Map the CPUs in a common freq domain.
+ * @all_cpu_data: Ptrs to CPU specific CPPC data including PSD info.
+ *
+ *     Return: 0 for success or negative value for err.
+ */
+int acpi_get_psd_map(struct cpudata **all_cpu_data)
+{
+       int count_target;
+       int retval = 0;
+       unsigned int i, j;
+       cpumask_var_t covered_cpus;
+       struct cpudata *pr, *match_pr;
+       struct acpi_psd_package *pdomain;
+       struct acpi_psd_package *match_pdomain;
+       struct cpc_desc *cpc_ptr, *match_cpc_ptr;
+
+       if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+               return -ENOMEM;
+
+       /*
+        * Now that we have _PSD data from all CPUs, lets setup P-state
+        * domain info.
+        */
+       for_each_possible_cpu(i) {
+               pr = all_cpu_data[i];
+               if (!pr)
+                       continue;
+
+               if (cpumask_test_cpu(i, covered_cpus))
+                       continue;
+
+               cpc_ptr = per_cpu(cpc_desc_ptr, i);
+               if (!cpc_ptr)
+                       continue;
+
+               pdomain = &(cpc_ptr->domain_info);
+               cpumask_set_cpu(i, pr->shared_cpu_map);
+               cpumask_set_cpu(i, covered_cpus);
+               if (pdomain->num_processors <= 1)
+                       continue;
+
+               /* Validate the Domain info */
+               count_target = pdomain->num_processors;
+               if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
+                       pr->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+               else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
+                       pr->shared_type = CPUFREQ_SHARED_TYPE_HW;
+               else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
+                       pr->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+
+               for_each_possible_cpu(j) {
+                       if (i == j)
+                               continue;
+
+                       match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
+                       if (!match_cpc_ptr)
+                               continue;
+
+                       match_pdomain = &(match_cpc_ptr->domain_info);
+                       if (match_pdomain->domain != pdomain->domain)
+                               continue;
+
+                       /* Here i and j are in the same domain */
+                       if (match_pdomain->num_processors != count_target) {
+                               retval = -EFAULT;
+                               goto err_ret;
+                       }
+
+                       if (pdomain->coord_type != match_pdomain->coord_type) {
+                               retval = -EFAULT;
+                               goto err_ret;
+                       }
+
+                       cpumask_set_cpu(j, covered_cpus);
+                       cpumask_set_cpu(j, pr->shared_cpu_map);
+               }
+
+               for_each_possible_cpu(j) {
+                       if (i == j)
+                               continue;
+
+                       match_pr = all_cpu_data[j];
+                       if (!match_pr)
+                               continue;
+
+                       match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
+                       if (!match_cpc_ptr)
+                               continue;
+
+                       match_pdomain = &(match_cpc_ptr->domain_info);
+                       if (match_pdomain->domain != pdomain->domain)
+                               continue;
+
+                       match_pr->shared_type = pr->shared_type;
+                       cpumask_copy(match_pr->shared_cpu_map,
+                                    pr->shared_cpu_map);
+               }
+       }
+
+err_ret:
+       for_each_possible_cpu(i) {
+               pr = all_cpu_data[i];
+               if (!pr)
+                       continue;
+
+               /* Assume no coordination on any error parsing domain info */
+               if (retval) {
+                       cpumask_clear(pr->shared_cpu_map);
+                       cpumask_set_cpu(i, pr->shared_cpu_map);
+                       pr->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+               }
+       }
+
+       free_cpumask_var(covered_cpus);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(acpi_get_psd_map);
+
+static int register_pcc_channel(int pcc_subspace_idx)
+{
+       struct acpi_pcct_subspace *cppc_ss;
+       unsigned int len;
+
+       if (pcc_subspace_idx >= 0) {
+               pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl,
+                               pcc_subspace_idx);
+
+               if (IS_ERR(pcc_channel)) {
+                       pr_err("Failed to find PCC communication channel\n");
+                       return -ENODEV;
+               }
+
+               /*
+                * The PCC mailbox controller driver should
+                * have parsed the PCCT (global table of all
+                * PCC channels) and stored pointers to the
+                * subspace communication region in con_priv.
+                */
+               cppc_ss = pcc_channel->con_priv;
+
+               if (!cppc_ss) {
+                       pr_err("No PCC subspace found for CPPC\n");
+                       return -ENODEV;
+               }
+
+               /*
+                * This is the shared communication region
+                * for the OS and Platform to communicate over.
+                */
+               comm_base_addr = cppc_ss->base_address;
+               len = cppc_ss->length;
+               pcc_cmd_delay = cppc_ss->min_turnaround_time;
+
+               pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len);
+               if (!pcc_comm_addr) {
+                       pr_err("Failed to ioremap PCC comm region mem\n");
+                       return -ENOMEM;
+               }
+
+               /* Set flag so that we dont come here for each CPU. */
+               pcc_channel_acquired = true;
+       }
+
+       return 0;
+}
+
+/*
+ * An example CPC table looks like the following.
+ *
+ *     Name(_CPC, Package()
+ *                     {
+ *                     17,
+ *                     NumEntries
+ *                     1,
+ *                     // Revision
+ *                     ResourceTemplate(){Register(PCC, 32, 0, 0x120, 2)},
+ *                     // Highest Performance
+ *                     ResourceTemplate(){Register(PCC, 32, 0, 0x124, 2)},
+ *                     // Nominal Performance
+ *                     ResourceTemplate(){Register(PCC, 32, 0, 0x128, 2)},
+ *                     // Lowest Nonlinear Performance
+ *                     ResourceTemplate(){Register(PCC, 32, 0, 0x12C, 2)},
+ *                     // Lowest Performance
+ *                     ResourceTemplate(){Register(PCC, 32, 0, 0x130, 2)},
+ *                     // Guaranteed Performance Register
+ *                     ResourceTemplate(){Register(PCC, 32, 0, 0x110, 2)},
+ *                     // Desired Performance Register
+ *                     ResourceTemplate(){Register(SystemMemory, 0, 0, 0, 0)},
+ *                     ..
+ *                     ..
+ *                     ..
+ *
+ *             }
+ * Each Register() encodes how to access that specific register.
+ * e.g. a sample PCC entry has the following encoding:
+ *
+ *     Register (
+ *             PCC,
+ *             AddressSpaceKeyword
+ *             8,
+ *             //RegisterBitWidth
+ *             8,
+ *             //RegisterBitOffset
+ *             0x30,
+ *             //RegisterAddress
+ *             9
+ *             //AccessSize (subspace ID)
+ *             0
+ *             )
+ *     }
+ */
+
+/**
+ * acpi_cppc_processor_probe - Search for per CPU _CPC objects.
+ * @pr: Ptr to acpi_processor containing this CPUs logical Id.
+ *
+ *     Return: 0 for success or negative value for err.
+ */
+int acpi_cppc_processor_probe(struct acpi_processor *pr)
+{
+       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *out_obj, *cpc_obj;
+       struct cpc_desc *cpc_ptr;
+       struct cpc_reg *gas_t;
+       acpi_handle handle = pr->handle;
+       unsigned int num_ent, i, cpc_rev;
+       acpi_status status;
+       int ret = -EFAULT;
+
+       /* Parse the ACPI _CPC table for this cpu. */
+       status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output,
+                       ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status)) {
+               ret = -ENODEV;
+               goto out_buf_free;
+       }
+
+       out_obj = (union acpi_object *) output.pointer;
+
+       cpc_ptr = kzalloc(sizeof(struct cpc_desc), GFP_KERNEL);
+       if (!cpc_ptr) {
+               ret = -ENOMEM;
+               goto out_buf_free;
+       }
+
+       /* First entry is NumEntries. */
+       cpc_obj = &out_obj->package.elements[0];
+       if (cpc_obj->type == ACPI_TYPE_INTEGER) {
+               num_ent = cpc_obj->integer.value;
+       } else {
+               pr_debug("Unexpected entry type(%d) for NumEntries\n",
+                               cpc_obj->type);
+               goto out_free;
+       }
+
+       /* Only support CPPCv2. Bail otherwise. */
+       if (num_ent != CPPC_NUM_ENT) {
+               pr_debug("Firmware exports %d entries. Expected: %d\n",
+                               num_ent, CPPC_NUM_ENT);
+               goto out_free;
+       }
+
+       /* Second entry should be revision. */
+       cpc_obj = &out_obj->package.elements[1];
+       if (cpc_obj->type == ACPI_TYPE_INTEGER) {
+               cpc_rev = cpc_obj->integer.value;
+       } else {
+               pr_debug("Unexpected entry type(%d) for Revision\n",
+                               cpc_obj->type);
+               goto out_free;
+       }
+
+       if (cpc_rev != CPPC_REV) {
+               pr_debug("Firmware exports revision:%d. Expected:%d\n",
+                               cpc_rev, CPPC_REV);
+               goto out_free;
+       }
+
+       /* Iterate through remaining entries in _CPC */
+       for (i = 2; i < num_ent; i++) {
+               cpc_obj = &out_obj->package.elements[i];
+
+               if (cpc_obj->type == ACPI_TYPE_INTEGER) {
+                       cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_INTEGER;
+                       cpc_ptr->cpc_regs[i-2].cpc_entry.int_value = cpc_obj->integer.value;
+               } else if (cpc_obj->type == ACPI_TYPE_BUFFER) {
+                       gas_t = (struct cpc_reg *)
+                               cpc_obj->buffer.pointer;
+
+                       /*
+                        * The PCC Subspace index is encoded inside
+                        * the CPC table entries. The same PCC index
+                        * will be used for all the PCC entries,
+                        * so extract it only once.
+                        */
+                       if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
+                               if (pcc_subspace_idx < 0)
+                                       pcc_subspace_idx = gas_t->access_width;
+                               else if (pcc_subspace_idx != gas_t->access_width) {
+                                       pr_debug("Mismatched PCC ids.\n");
+                                       goto out_free;
+                               }
+                       } else if (gas_t->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+                               /* Support only PCC and SYS MEM type regs */
+                               pr_debug("Unsupported register type: %d\n", gas_t->space_id);
+                               goto out_free;
+                       }
+
+                       cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER;
+                       memcpy(&cpc_ptr->cpc_regs[i-2].cpc_entry.reg, gas_t, sizeof(*gas_t));
+               } else {
+                       pr_debug("Err in entry:%d in CPC table of CPU:%d \n", i, pr->id);
+                       goto out_free;
+               }
+       }
+       /* Store CPU Logical ID */
+       cpc_ptr->cpu_id = pr->id;
+
+       /* Plug it into this CPUs CPC descriptor. */
+       per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
+
+       /* Parse PSD data for this CPU */
+       ret = acpi_get_psd(cpc_ptr, handle);
+       if (ret)
+               goto out_free;
+
+       /* Register PCC channel once for all CPUs. */
+       if (!pcc_channel_acquired) {
+               ret = register_pcc_channel(pcc_subspace_idx);
+               if (ret)
+                       goto out_free;
+       }
+
+       /* Everything looks okay */
+       pr_debug("Parsed CPC struct for CPU: %d\n", pr->id);
+
+       kfree(output.pointer);
+       return 0;
+
+out_free:
+       kfree(cpc_ptr);
+
+out_buf_free:
+       kfree(output.pointer);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_cppc_processor_probe);
+
+/**
+ * acpi_cppc_processor_exit - Cleanup CPC structs.
+ * @pr: Ptr to acpi_processor containing this CPUs logical Id.
+ *
+ * Return: Void
+ */
+void acpi_cppc_processor_exit(struct acpi_processor *pr)
+{
+       struct cpc_desc *cpc_ptr;
+       cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
+       kfree(cpc_ptr);
+}
+EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
+
+static u64 get_phys_addr(struct cpc_reg *reg)
+{
+       /* PCC communication addr space begins at byte offset 0x8. */
+       if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
+               return (u64)comm_base_addr + 0x8 + reg->address;
+       else
+               return reg->address;
+}
+
+static void cpc_read(struct cpc_reg *reg, u64 *val)
+{
+       u64 addr = get_phys_addr(reg);
+
+       acpi_os_read_memory((acpi_physical_address)addr,
+                       val, reg->bit_width);
+}
+
+static void cpc_write(struct cpc_reg *reg, u64 val)
+{
+       u64 addr = get_phys_addr(reg);
+
+       acpi_os_write_memory((acpi_physical_address)addr,
+                       val, reg->bit_width);
+}
+
+/**
+ * cppc_get_perf_caps - Get a CPUs performance capabilities.
+ * @cpunum: CPU from which to get capabilities info.
+ * @perf_caps: ptr to cppc_perf_caps. See cppc_acpi.h
+ *
+ * Return: 0 for success with perf_caps populated else -ERRNO.
+ */
+int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
+{
+       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
+       struct cpc_register_resource *highest_reg, *lowest_reg, *ref_perf,
+                                                                *nom_perf;
+       u64 high, low, ref, nom;
+       int ret = 0;
+
+       if (!cpc_desc) {
+               pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
+               return -ENODEV;
+       }
+
+       highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF];
+       lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
+       ref_perf = &cpc_desc->cpc_regs[REFERENCE_PERF];
+       nom_perf = &cpc_desc->cpc_regs[NOMINAL_PERF];
+
+       spin_lock(&pcc_lock);
+
+       /* Are any of the regs PCC ?*/
+       if ((highest_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
+                       (lowest_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
+                       (ref_perf->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
+                       (nom_perf->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
+               /* Ring doorbell once to update PCC subspace */
+               if (send_pcc_cmd(CMD_READ)) {
+                       ret = -EIO;
+                       goto out_err;
+               }
+       }
+
+       cpc_read(&highest_reg->cpc_entry.reg, &high);
+       perf_caps->highest_perf = high;
+
+       cpc_read(&lowest_reg->cpc_entry.reg, &low);
+       perf_caps->lowest_perf = low;
+
+       cpc_read(&ref_perf->cpc_entry.reg, &ref);
+       perf_caps->reference_perf = ref;
+
+       cpc_read(&nom_perf->cpc_entry.reg, &nom);
+       perf_caps->nominal_perf = nom;
+
+       if (!ref)
+               perf_caps->reference_perf = perf_caps->nominal_perf;
+
+       if (!high || !low || !nom)
+               ret = -EFAULT;
+
+out_err:
+       spin_unlock(&pcc_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
+
+/**
+ * cppc_get_perf_ctrs - Read a CPUs performance feedback counters.
+ * @cpunum: CPU from which to read counters.
+ * @perf_fb_ctrs: ptr to cppc_perf_fb_ctrs. See cppc_acpi.h
+ *
+ * Return: 0 for success with perf_fb_ctrs populated else -ERRNO.
+ */
+int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
+{
+       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
+       struct cpc_register_resource *delivered_reg, *reference_reg;
+       u64 delivered, reference;
+       int ret = 0;
+
+       if (!cpc_desc) {
+               pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
+               return -ENODEV;
+       }
+
+       delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR];
+       reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR];
+
+       spin_lock(&pcc_lock);
+
+       /* Are any of the regs PCC ?*/
+       if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
+                       (reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
+               /* Ring doorbell once to update PCC subspace */
+               if (send_pcc_cmd(CMD_READ)) {
+                       ret = -EIO;
+                       goto out_err;
+               }
+       }
+
+       cpc_read(&delivered_reg->cpc_entry.reg, &delivered);
+       cpc_read(&reference_reg->cpc_entry.reg, &reference);
+
+       if (!delivered || !reference) {
+               ret = -EFAULT;
+               goto out_err;
+       }
+
+       perf_fb_ctrs->delivered = delivered;
+       perf_fb_ctrs->reference = reference;
+
+       perf_fb_ctrs->delivered -= perf_fb_ctrs->prev_delivered;
+       perf_fb_ctrs->reference -= perf_fb_ctrs->prev_reference;
+
+       perf_fb_ctrs->prev_delivered = delivered;
+       perf_fb_ctrs->prev_reference = reference;
+
+out_err:
+       spin_unlock(&pcc_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs);
+
+/**
+ * cppc_set_perf - Set a CPUs performance controls.
+ * @cpu: CPU for which to set performance controls.
+ * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
+ *
+ * Return: 0 for success, -ERRNO otherwise.
+ */
+int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
+{
+       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+       struct cpc_register_resource *desired_reg;
+       int ret = 0;
+
+       if (!cpc_desc) {
+               pr_debug("No CPC descriptor for CPU:%d\n", cpu);
+               return -ENODEV;
+       }
+
+       desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
+
+       spin_lock(&pcc_lock);
+
+       /*
+        * Skip writing MIN/MAX until Linux knows how to come up with
+        * useful values.
+        */
+       cpc_write(&desired_reg->cpc_entry.reg, perf_ctrls->desired_perf);
+
+       /* Is this a PCC reg ?*/
+       if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
+               /* Ring doorbell so Remote can get our perf request. */
+               if (send_pcc_cmd(CMD_WRITE))
+                       ret = -EIO;
+       }
+
+       spin_unlock(&pcc_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cppc_set_perf);
index 4806b7f856c46047bb0b4bd38bbc66717e33a6e0..08a02cdc737c193d608970b6eec0b45781137d76 100644 (file)
@@ -962,23 +962,6 @@ int acpi_subsys_prepare(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
 
-/**
- * acpi_subsys_complete - Finalize device's resume during system resume.
- * @dev: Device to handle.
- */
-void acpi_subsys_complete(struct device *dev)
-{
-       pm_generic_complete(dev);
-       /*
-        * If the device had been runtime-suspended before the system went into
-        * the sleep state it is going out of and it has never been resumed till
-        * now, resume it in case the firmware powered it up.
-        */
-       if (dev->power.direct_complete)
-               pm_request_resume(dev);
-}
-EXPORT_SYMBOL_GPL(acpi_subsys_complete);
-
 /**
  * acpi_subsys_suspend - Run the device driver's suspend callback.
  * @dev: Device to handle.
@@ -1047,7 +1030,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
                .runtime_resume = acpi_subsys_runtime_resume,
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
-               .complete = acpi_subsys_complete,
+               .complete = pm_complete_with_resume_check,
                .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_subsys_suspend_late,
                .resume_early = acpi_subsys_resume_early,
index 4ab4582e586b750a287b8b6744ecb3e0f480593f..707cf6213bc2888b4cc1e09a0f851d232b9521c0 100644 (file)
 
 #include "internal.h"
 
+static ssize_t acpi_object_path(acpi_handle handle, char *buf)
+{
+       struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+       int result;
+
+       result = acpi_get_name(handle, ACPI_FULL_PATHNAME, &path);
+       if (result)
+               return result;
+
+       result = sprintf(buf, "%s\n", (char*)path.pointer);
+       kfree(path.pointer);
+       return result;
+}
+
+struct acpi_data_node_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct acpi_data_node *, char *);
+       ssize_t (*store)(struct acpi_data_node *, const char *, size_t count);
+};
+
+#define DATA_NODE_ATTR(_name)                  \
+       static struct acpi_data_node_attr data_node_##_name =   \
+               __ATTR(_name, 0444, data_node_show_##_name, NULL)
+
+static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf)
+{
+       return acpi_object_path(dn->handle, buf);
+}
+
+DATA_NODE_ATTR(path);
+
+static struct attribute *acpi_data_node_default_attrs[] = {
+       &data_node_path.attr,
+       NULL
+};
+
+#define to_data_node(k) container_of(k, struct acpi_data_node, kobj)
+#define to_attr(a) container_of(a, struct acpi_data_node_attr, attr)
+
+static ssize_t acpi_data_node_attr_show(struct kobject *kobj,
+                                       struct attribute *attr, char *buf)
+{
+       struct acpi_data_node *dn = to_data_node(kobj);
+       struct acpi_data_node_attr *dn_attr = to_attr(attr);
+
+       return dn_attr->show ? dn_attr->show(dn, buf) : -ENXIO;
+}
+
+static const struct sysfs_ops acpi_data_node_sysfs_ops = {
+       .show   = acpi_data_node_attr_show,
+};
+
+static void acpi_data_node_release(struct kobject *kobj)
+{
+       struct acpi_data_node *dn = to_data_node(kobj);
+       complete(&dn->kobj_done);
+}
+
+static struct kobj_type acpi_data_node_ktype = {
+       .sysfs_ops = &acpi_data_node_sysfs_ops,
+       .default_attrs = acpi_data_node_default_attrs,
+       .release = acpi_data_node_release,
+};
+
+static void acpi_expose_nondev_subnodes(struct kobject *kobj,
+                                       struct acpi_device_data *data)
+{
+       struct list_head *list = &data->subnodes;
+       struct acpi_data_node *dn;
+
+       if (list_empty(list))
+               return;
+
+       list_for_each_entry(dn, list, sibling) {
+               int ret;
+
+               init_completion(&dn->kobj_done);
+               ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
+                                          kobj, dn->name);
+               if (ret)
+                       acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
+               else
+                       acpi_expose_nondev_subnodes(&dn->kobj, &dn->data);
+       }
+}
+
+static void acpi_hide_nondev_subnodes(struct acpi_device_data *data)
+{
+       struct list_head *list = &data->subnodes;
+       struct acpi_data_node *dn;
+
+       if (list_empty(list))
+               return;
+
+       list_for_each_entry_reverse(dn, list, sibling) {
+               acpi_hide_nondev_subnodes(&dn->data);
+               kobject_put(&dn->kobj);
+       }
+}
+
 /**
  * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
  * @acpi_dev: ACPI device object.
@@ -323,20 +423,12 @@ static ssize_t acpi_device_adr_show(struct device *dev,
 }
 static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
 
-static ssize_t
-acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t acpi_device_path_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
        struct acpi_device *acpi_dev = to_acpi_device(dev);
-       struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
-       int result;
-
-       result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
-       if (result)
-               goto end;
 
-       result = sprintf(buf, "%s\n", (char*)path.pointer);
-       kfree(path.pointer);
-end:
-       return result;
+       return acpi_object_path(acpi_dev->handle, buf);
 }
 static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
 
@@ -475,6 +567,8 @@ int acpi_device_setup_files(struct acpi_device *dev)
                                                    &dev_attr_real_power_state);
        }
 
+       acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data);
+
 end:
        return result;
 }
@@ -485,6 +579,8 @@ end:
  */
 void acpi_device_remove_files(struct acpi_device *dev)
 {
+       acpi_hide_nondev_subnodes(&dev->data);
+
        if (dev->flags.power_manageable) {
                device_remove_file(&dev->dev, &dev_attr_power_state);
                if (dev->power.flags.power_resources)
index 42c66b64c12cefd8c1491e7b91af138b86ddf5af..f61a7c83454063a5e77ebf35e13cb4bb1431891b 100644 (file)
@@ -441,17 +441,31 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
 
 static bool acpi_ec_guard_event(struct acpi_ec *ec)
 {
+       bool guarded = true;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
+       /*
+        * If firmware SCI_EVT clearing timing is "event", we actually
+        * don't know when the SCI_EVT will be cleared by firmware after
+        * evaluating _Qxx, so we need to re-check SCI_EVT after waiting an
+        * acceptable period.
+        *
+        * The guarding period begins when EC_FLAGS_QUERY_PENDING is
+        * flagged, which means SCI_EVT check has just been performed.
+        * But if the current transaction is ACPI_EC_COMMAND_QUERY, the
+        * guarding should have already been performed (via
+        * EC_FLAGS_QUERY_GUARDING) and should not be applied so that the
+        * ACPI_EC_COMMAND_QUERY transaction can be transitioned into
+        * ACPI_EC_COMMAND_POLL state immediately.
+        */
        if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
            ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY ||
            !test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) ||
            (ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY))
-               return false;
-
-       /*
-        * Postpone the query submission to allow the firmware to proceed,
-        * we shouldn't check SCI_EVT before the firmware reflagging it.
-        */
-       return true;
+               guarded = false;
+       spin_unlock_irqrestore(&ec->lock, flags);
+       return guarded;
 }
 
 static int ec_transaction_polled(struct acpi_ec *ec)
@@ -597,6 +611,7 @@ static int ec_guard(struct acpi_ec *ec)
        unsigned long guard = usecs_to_jiffies(ec_polling_guard);
        unsigned long timeout = ec->timestamp + guard;
 
+       /* Ensure guarding period before polling EC status */
        do {
                if (ec_busy_polling) {
                        /* Perform busy polling */
@@ -606,11 +621,13 @@ static int ec_guard(struct acpi_ec *ec)
                } else {
                        /*
                         * Perform wait polling
-                        *
-                        * For SCI_EVT clearing timing of "event",
-                        * performing guarding before re-checking the
-                        * SCI_EVT. Otherwise, such guarding is not needed
-                        * due to the old practices.
+                        * 1. Wait the transaction to be completed by the
+                        *    GPE handler after the transaction enters
+                        *    ACPI_EC_COMMAND_POLL state.
+                        * 2. A special guarding logic is also required
+                        *    for event clearing mode "event" before the
+                        *    transaction enters ACPI_EC_COMMAND_POLL
+                        *    state.
                         */
                        if (!ec_transaction_polled(ec) &&
                            !acpi_ec_guard_event(ec))
@@ -620,7 +637,6 @@ static int ec_guard(struct acpi_ec *ec)
                                               guard))
                                return 0;
                }
-               /* Guard the register accesses for the polling modes */
        } while (time_before(jiffies, timeout));
        return -ETIME;
 }
@@ -929,6 +945,23 @@ acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
        return handler;
 }
 
+static struct acpi_ec_query_handler *
+acpi_ec_get_query_handler_by_value(struct acpi_ec *ec, u8 value)
+{
+       struct acpi_ec_query_handler *handler;
+       bool found = false;
+
+       mutex_lock(&ec->mutex);
+       list_for_each_entry(handler, &ec->list, node) {
+               if (value == handler->query_bit) {
+                       found = true;
+                       break;
+               }
+       }
+       mutex_unlock(&ec->mutex);
+       return found ? acpi_ec_get_query_handler(handler) : NULL;
+}
+
 static void acpi_ec_query_handler_release(struct kref *kref)
 {
        struct acpi_ec_query_handler *handler =
@@ -964,14 +997,15 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 }
 EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
 
-void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+static void acpi_ec_remove_query_handlers(struct acpi_ec *ec,
+                                         bool remove_all, u8 query_bit)
 {
        struct acpi_ec_query_handler *handler, *tmp;
        LIST_HEAD(free_list);
 
        mutex_lock(&ec->mutex);
        list_for_each_entry_safe(handler, tmp, &ec->list, node) {
-               if (query_bit == handler->query_bit) {
+               if (remove_all || query_bit == handler->query_bit) {
                        list_del_init(&handler->node);
                        list_add(&handler->node, &free_list);
                }
@@ -980,6 +1014,11 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
        list_for_each_entry_safe(handler, tmp, &free_list, node)
                acpi_ec_put_query_handler(handler);
 }
+
+void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+{
+       acpi_ec_remove_query_handlers(ec, false, query_bit);
+}
 EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 
 static struct acpi_ec_query *acpi_ec_create_query(u8 *pval)
@@ -1025,7 +1064,6 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
 {
        u8 value = 0;
        int result;
-       struct acpi_ec_query_handler *handler;
        struct acpi_ec_query *q;
 
        q = acpi_ec_create_query(&value);
@@ -1043,25 +1081,26 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
        if (result)
                goto err_exit;
 
-       mutex_lock(&ec->mutex);
-       result = -ENODATA;
-       list_for_each_entry(handler, &ec->list, node) {
-               if (value == handler->query_bit) {
-                       result = 0;
-                       q->handler = acpi_ec_get_query_handler(handler);
-                       ec_dbg_evt("Query(0x%02x) scheduled",
-                                  q->handler->query_bit);
-                       /*
-                        * It is reported that _Qxx are evaluated in a
-                        * parallel way on Windows:
-                        * https://bugzilla.kernel.org/show_bug.cgi?id=94411
-                        */
-                       if (!schedule_work(&q->work))
-                               result = -EBUSY;
-                       break;
-               }
+       q->handler = acpi_ec_get_query_handler_by_value(ec, value);
+       if (!q->handler) {
+               result = -ENODATA;
+               goto err_exit;
+       }
+
+       /*
+        * It is reported that _Qxx are evaluated in a parallel way on
+        * Windows:
+        * https://bugzilla.kernel.org/show_bug.cgi?id=94411
+        *
+        * Put this log entry before schedule_work() in order to make
+        * it appearing before any other log entries occurred during the
+        * work queue execution.
+        */
+       ec_dbg_evt("Query(0x%02x) scheduled", value);
+       if (!schedule_work(&q->work)) {
+               ec_dbg_evt("Query(0x%02x) overlapped", value);
+               result = -EBUSY;
        }
-       mutex_unlock(&ec->mutex);
 
 err_exit:
        if (result && q)
@@ -1354,19 +1393,13 @@ static int acpi_ec_add(struct acpi_device *device)
 static int acpi_ec_remove(struct acpi_device *device)
 {
        struct acpi_ec *ec;
-       struct acpi_ec_query_handler *handler, *tmp;
 
        if (!device)
                return -EINVAL;
 
        ec = acpi_driver_data(device);
        ec_remove_handlers(ec);
-       mutex_lock(&ec->mutex);
-       list_for_each_entry_safe(handler, tmp, &ec->list, node) {
-               list_del(&handler->node);
-               kfree(handler);
-       }
-       mutex_unlock(&ec->mutex);
+       acpi_ec_remove_query_handlers(ec, true, 0);
        release_region(ec->data_addr, 1);
        release_region(ec->command_addr, 1);
        device->driver_data = NULL;
index b9657af751d1051d9b44ed2a22e2c347dd9c9846..1470ae4f98c07ce6e358bd53bf17b0c0b209b1cb 100644 (file)
@@ -351,13 +351,12 @@ static int acpi_platform_notify_remove(struct device *dev)
        return 0;
 }
 
-int __init init_acpi_device_notify(void)
+void __init init_acpi_device_notify(void)
 {
        if (platform_notify || platform_notify_remove) {
                printk(KERN_ERR PREFIX "Can't use platform_notify\n");
-               return 0;
+               return;
        }
        platform_notify = acpi_platform_notify;
        platform_notify_remove = acpi_platform_notify_remove;
-       return 0;
 }
index 9e426210c2a8ea6a283bc04d9dc8bd1ac739370e..c31787bef2d323145f38b6a5b6884713a953df20 100644 (file)
@@ -21,7 +21,7 @@
 #define PREFIX "ACPI: "
 
 acpi_status acpi_os_initialize1(void);
-int init_acpi_device_notify(void);
+void init_acpi_device_notify(void);
 int acpi_scan_init(void);
 void acpi_pci_root_init(void);
 void acpi_pci_link_init(void);
@@ -179,13 +179,13 @@ static inline int acpi_sleep_init(void) { return -ENXIO; }
 #endif
 
 #ifdef CONFIG_ACPI_SLEEP
-int acpi_sleep_proc_init(void);
+void acpi_sleep_proc_init(void);
 int suspend_nvs_alloc(void);
 void suspend_nvs_free(void);
 int suspend_nvs_save(void);
 void suspend_nvs_restore(void);
 #else
-static inline int acpi_sleep_proc_init(void) { return 0; }
+static inline void acpi_sleep_proc_init(void) {}
 static inline int suspend_nvs_alloc(void) { return 0; }
 static inline void suspend_nvs_free(void) {}
 static inline int suspend_nvs_save(void) { return 0; }
index a14ee291d1a70cf0dc053e351435de16ba00e472..6e26761a27dae90d0671b1edf38b2e8533d56df3 100644 (file)
@@ -706,7 +706,7 @@ static ssize_t flags_show(struct device *dev,
                flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
                flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
                flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
-               flags & ACPI_NFIT_MEM_ARMED ? "not_armed " : "",
+               flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
                flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
 }
 static DEVICE_ATTR_RO(flags);
@@ -815,7 +815,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
                        flags |= NDD_ALIASING;
 
                mem_flags = __to_nfit_memdev(nfit_mem)->flags;
-               if (mem_flags & ACPI_NFIT_MEM_ARMED)
+               if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
                        flags |= NDD_UNARMED;
 
                rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
@@ -839,7 +839,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
                  mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
                  mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
                  mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
-                 mem_flags & ACPI_NFIT_MEM_ARMED ? " not_armed" : "");
+                 mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
 
        }
 
index 7e740156b9c2996986e0283e2bdb5d84512929ee..329a1eba0c164e79cac859c28afeab456755ca89 100644 (file)
@@ -24,7 +24,7 @@
 #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
 #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
                | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
-               | ACPI_NFIT_MEM_ARMED)
+               | ACPI_NFIT_MEM_NOT_ARMED)
 
 enum nfit_uuids {
        NFIT_SPA_VOLATILE,
index 7d0848190b75e758c1243893bed084c1075672fd..32d684af0ec7c8a36781e5b7e712c7dd0e65b241 100644 (file)
@@ -66,8 +66,6 @@ struct acpi_os_dpc {
 /* stuff for debugger support */
 int acpi_in_debugger;
 EXPORT_SYMBOL(acpi_in_debugger);
-
-extern char line_buf[80];
 #endif                         /*ENABLE_DEBUGGER */
 
 static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
@@ -81,6 +79,7 @@ static struct workqueue_struct *kacpid_wq;
 static struct workqueue_struct *kacpi_notify_wq;
 static struct workqueue_struct *kacpi_hotplug_wq;
 static bool acpi_os_initialized;
+unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
 
 /*
  * This list of permanent mappings is for memory that may be accessed from
@@ -856,17 +855,19 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
                acpi_irq_handler = NULL;
                return AE_NOT_ACQUIRED;
        }
+       acpi_sci_irq = irq;
 
        return AE_OK;
 }
 
-acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
+acpi_status acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler handler)
 {
-       if (irq != acpi_gbl_FADT.sci_interrupt)
+       if (gsi != acpi_gbl_FADT.sci_interrupt || !acpi_sci_irq_valid())
                return AE_BAD_PARAMETER;
 
-       free_irq(irq, acpi_irq);
+       free_irq(acpi_sci_irq, acpi_irq);
        acpi_irq_handler = NULL;
+       acpi_sci_irq = INVALID_ACPI_IRQ;
 
        return AE_OK;
 }
@@ -1180,8 +1181,8 @@ void acpi_os_wait_events_complete(void)
         * Make sure the GPE handler or the fixed event handler is not used
         * on another CPU after removal.
         */
-       if (acpi_irq_handler)
-               synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
+       if (acpi_sci_irq_valid())
+               synchronize_hardirq(acpi_sci_irq);
        flush_workqueue(kacpid_wq);
        flush_workqueue(kacpi_notify_wq);
 }
@@ -1345,15 +1346,13 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
        return AE_OK;
 }
 
-#ifdef ACPI_FUTURE_USAGE
-u32 acpi_os_get_line(char *buffer)
+acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 {
-
 #ifdef ENABLE_DEBUGGER
        if (acpi_in_debugger) {
                u32 chars;
 
-               kdb_read(buffer, sizeof(line_buf));
+               kdb_read(buffer, buffer_length);
 
                /* remove the CR kdb includes */
                chars = strlen(buffer) - 1;
@@ -1361,9 +1360,8 @@ u32 acpi_os_get_line(char *buffer)
        }
 #endif
 
-       return 0;
+       return AE_OK;
 }
-#endif                         /*  ACPI_FUTURE_USAGE  */
 
 acpi_status acpi_os_signal(u32 function, void *info)
 {
index 393706a5261b0d82f58f877e49581a521eb1d672..850d7bf0c873fb64af77ada90e971a733527e2bd 100644 (file)
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct acpi_device *device)
        kfree(root);
 }
 
+/*
+ * Following code to support acpi_pci_root_create() is copied from
+ * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64
+ * and ARM64.
+ */
+static void acpi_pci_root_validate_resources(struct device *dev,
+                                            struct list_head *resources,
+                                            unsigned long type)
+{
+       LIST_HEAD(list);
+       struct resource *res1, *res2, *root = NULL;
+       struct resource_entry *tmp, *entry, *entry2;
+
+       BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+       root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+       list_splice_init(resources, &list);
+       resource_list_for_each_entry_safe(entry, tmp, &list) {
+               bool free = false;
+               resource_size_t end;
+
+               res1 = entry->res;
+               if (!(res1->flags & type))
+                       goto next;
+
+               /* Exclude non-addressable range or non-addressable portion */
+               end = min(res1->end, root->end);
+               if (end <= res1->start) {
+                       dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+                                res1);
+                       free = true;
+                       goto next;
+               } else if (res1->end != end) {
+                       dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+                                res1, (unsigned long long)end + 1,
+                                (unsigned long long)res1->end);
+                       res1->end = end;
+               }
+
+               resource_list_for_each_entry(entry2, resources) {
+                       res2 = entry2->res;
+                       if (!(res2->flags & type))
+                               continue;
+
+                       /*
+                        * I don't like throwing away windows because then
+                        * our resources no longer match the ACPI _CRS, but
+                        * the kernel resource tree doesn't allow overlaps.
+                        */
+                       if (resource_overlaps(res1, res2)) {
+                               res2->start = min(res1->start, res2->start);
+                               res2->end = max(res1->end, res2->end);
+                               dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+                                        res2, res1);
+                               free = true;
+                               goto next;
+                       }
+               }
+
+next:
+               resource_list_del(entry);
+               if (free)
+                       resource_list_free_entry(entry);
+               else
+                       resource_list_add_tail(entry, resources);
+       }
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+       int ret;
+       struct list_head *list = &info->resources;
+       struct acpi_device *device = info->bridge;
+       struct resource_entry *entry, *tmp;
+       unsigned long flags;
+
+       flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+       ret = acpi_dev_get_resources(device, list,
+                                    acpi_dev_filter_resource_type_cb,
+                                    (void *)flags);
+       if (ret < 0)
+               dev_warn(&device->dev,
+                        "failed to parse _CRS method, error code %d\n", ret);
+       else if (ret == 0)
+               dev_dbg(&device->dev,
+                       "no IO and memory resources present in _CRS\n");
+       else {
+               resource_list_for_each_entry_safe(entry, tmp, list) {
+                       if (entry->res->flags & IORESOURCE_DISABLED)
+                               resource_list_destroy_entry(entry);
+                       else
+                               entry->res->name = info->name;
+               }
+               acpi_pci_root_validate_resources(&device->dev, list,
+                                                IORESOURCE_MEM);
+               acpi_pci_root_validate_resources(&device->dev, list,
+                                                IORESOURCE_IO);
+       }
+
+       return ret;
+}
+
+static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info)
+{
+       struct resource_entry *entry, *tmp;
+       struct resource *res, *conflict, *root = NULL;
+
+       resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
+               res = entry->res;
+               if (res->flags & IORESOURCE_MEM)
+                       root = &iomem_resource;
+               else if (res->flags & IORESOURCE_IO)
+                       root = &ioport_resource;
+               else
+                       continue;
+
+               conflict = insert_resource_conflict(root, res);
+               if (conflict) {
+                       dev_info(&info->bridge->dev,
+                                "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+                                res, conflict->name, conflict);
+                       resource_list_destroy_entry(entry);
+               }
+       }
+}
+
+static void __acpi_pci_root_release_info(struct acpi_pci_root_info *info)
+{
+       struct resource *res;
+       struct resource_entry *entry, *tmp;
+
+       if (!info)
+               return;
+
+       resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
+               res = entry->res;
+               if (res->parent &&
+                   (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+                       release_resource(res);
+               resource_list_destroy_entry(entry);
+       }
+
+       info->ops->release_info(info);
+}
+
+static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
+{
+       struct resource *res;
+       struct resource_entry *entry;
+
+       resource_list_for_each_entry(entry, &bridge->windows) {
+               res = entry->res;
+               if (res->parent &&
+                   (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+                       release_resource(res);
+       }
+       __acpi_pci_root_release_info(bridge->release_data);
+}
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+                                    struct acpi_pci_root_ops *ops,
+                                    struct acpi_pci_root_info *info,
+                                    void *sysdata)
+{
+       int ret, busnum = root->secondary.start;
+       struct acpi_device *device = root->device;
+       int node = acpi_get_node(device->handle);
+       struct pci_bus *bus;
+
+       info->root = root;
+       info->bridge = device;
+       info->ops = ops;
+       INIT_LIST_HEAD(&info->resources);
+       snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+                root->segment, busnum);
+
+       if (ops->init_info && ops->init_info(info))
+               goto out_release_info;
+       if (ops->prepare_resources)
+               ret = ops->prepare_resources(info);
+       else
+               ret = acpi_pci_probe_root_resources(info);
+       if (ret < 0)
+               goto out_release_info;
+
+       pci_acpi_root_add_resources(info);
+       pci_add_resource(&info->resources, &root->secondary);
+       bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+                                 sysdata, &info->resources);
+       if (!bus)
+               goto out_release_info;
+
+       pci_scan_child_bus(bus);
+       pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
+                                   acpi_pci_root_release_info, info);
+       if (node != NUMA_NO_NODE)
+               dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
+       return bus;
+
+out_release_info:
+       __acpi_pci_root_release_info(info);
+       return NULL;
+}
+
 void __init acpi_pci_root_init(void)
 {
        acpi_hest_init();
index 75c28eae88604903ac518fc0fe4ebe83f2e2669e..2a358154b770dda2a603600cb1348fc2514aabae 100644 (file)
@@ -144,11 +144,9 @@ static const struct file_operations acpi_system_wakeup_device_fops = {
        .release = single_release,
 };
 
-int __init acpi_sleep_proc_init(void)
+void __init acpi_sleep_proc_init(void)
 {
        /* 'wakeup device' [R/W] */
        proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
                    acpi_root_dir, &acpi_system_wakeup_device_fops);
-
-       return 0;
 }
index 51e658f21e956fd66895d431971bb56449c74e56..f4e02ae93f585fbb8de42c09d4d0fb32d2751887 100644 (file)
@@ -242,6 +242,10 @@ static int __acpi_processor_start(struct acpi_device *device)
        if (pr->flags.need_hotplug_init)
                return 0;
 
+       result = acpi_cppc_processor_probe(pr);
+       if (result)
+               return -ENODEV;
+
        if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
                acpi_processor_power_init(pr);
 
@@ -287,6 +291,8 @@ static int acpi_processor_stop(struct device *dev)
 
        acpi_pss_perf_exit(pr, device);
 
+       acpi_cppc_processor_exit(pr);
+
        return 0;
 }
 
index 6d99450549c59dc1990598a0ad801049bc241b03..88f4306744c0aa23cb1b8b38ecf7f8df9c38b5f1 100644 (file)
 
 #include "internal.h"
 
+static int acpi_data_get_property_array(struct acpi_device_data *data,
+                                       const char *name,
+                                       acpi_object_type type,
+                                       const union acpi_object **obj);
+
 /* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
 static const u8 prp_uuid[16] = {
        0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
        0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
 };
+/* ACPI _DSD data subnodes UUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
+static const u8 ads_uuid[16] = {
+       0xe6, 0xe3, 0xb8, 0xdb, 0x86, 0x58, 0xa6, 0x4b,
+       0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b
+};
+
+static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
+                                          const union acpi_object *desc,
+                                          struct acpi_device_data *data);
+static bool acpi_extract_properties(const union acpi_object *desc,
+                                   struct acpi_device_data *data);
+
+static bool acpi_nondev_subnode_ok(acpi_handle scope,
+                                  const union acpi_object *link,
+                                  struct list_head *list)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       struct acpi_data_node *dn;
+       acpi_handle handle;
+       acpi_status status;
+
+       dn = kzalloc(sizeof(*dn), GFP_KERNEL);
+       if (!dn)
+               return false;
+
+       dn->name = link->package.elements[0].string.pointer;
+       dn->fwnode.type = FWNODE_ACPI_DATA;
+       INIT_LIST_HEAD(&dn->data.subnodes);
+
+       status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
+                                &handle);
+       if (ACPI_FAILURE(status))
+               goto fail;
+
+       status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
+                                           ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status))
+               goto fail;
+
+       if (acpi_extract_properties(buf.pointer, &dn->data))
+               dn->handle = handle;
+
+       /*
+        * The scope for the subnode object lookup is the one of the namespace
+        * node (device) containing the object that has returned the package.
+        * That is, it's the scope of that object's parent.
+        */
+       status = acpi_get_parent(handle, &scope);
+       if (ACPI_SUCCESS(status)
+           && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
+               dn->handle = handle;
+
+       if (dn->handle) {
+               dn->data.pointer = buf.pointer;
+               list_add_tail(&dn->sibling, list);
+               return true;
+       }
+
+       acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
+
+ fail:
+       ACPI_FREE(buf.pointer);
+       kfree(dn);
+       return false;
+}
+
+static int acpi_add_nondev_subnodes(acpi_handle scope,
+                                   const union acpi_object *links,
+                                   struct list_head *list)
+{
+       bool ret = false;
+       int i;
+
+       for (i = 0; i < links->package.count; i++) {
+               const union acpi_object *link;
+
+               link = &links->package.elements[i];
+               /* Only two elements allowed, both must be strings. */
+               if (link->package.count == 2
+                   && link->package.elements[0].type == ACPI_TYPE_STRING
+                   && link->package.elements[1].type == ACPI_TYPE_STRING
+                   && acpi_nondev_subnode_ok(scope, link, list))
+                       ret = true;
+       }
+
+       return ret;
+}
+
+static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
+                                          const union acpi_object *desc,
+                                          struct acpi_device_data *data)
+{
+       int i;
+
+       /* Look for the ACPI data subnodes UUID. */
+       for (i = 0; i < desc->package.count; i += 2) {
+               const union acpi_object *uuid, *links;
+
+               uuid = &desc->package.elements[i];
+               links = &desc->package.elements[i + 1];
+
+               /*
+                * The first element must be a UUID and the second one must be
+                * a package.
+                */
+               if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+                   || links->type != ACPI_TYPE_PACKAGE)
+                       break;
+
+               if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid)))
+                       continue;
+
+               return acpi_add_nondev_subnodes(scope, links, &data->subnodes);
+       }
+
+       return false;
+}
 
 static bool acpi_property_value_ok(const union acpi_object *value)
 {
@@ -81,8 +203,8 @@ static void acpi_init_of_compatible(struct acpi_device *adev)
        const union acpi_object *of_compatible;
        int ret;
 
-       ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
-                                         &of_compatible);
+       ret = acpi_data_get_property_array(&adev->data, "compatible",
+                                          ACPI_TYPE_STRING, &of_compatible);
        if (ret) {
                ret = acpi_dev_get_property(adev, "compatible",
                                            ACPI_TYPE_STRING, &of_compatible);
@@ -100,34 +222,13 @@ static void acpi_init_of_compatible(struct acpi_device *adev)
        adev->flags.of_compatible_ok = 1;
 }
 
-void acpi_init_properties(struct acpi_device *adev)
+static bool acpi_extract_properties(const union acpi_object *desc,
+                                   struct acpi_device_data *data)
 {
-       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
-       bool acpi_of = false;
-       struct acpi_hardware_id *hwid;
-       const union acpi_object *desc;
-       acpi_status status;
        int i;
 
-       /*
-        * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
-        * Device Tree compatible properties for this device.
-        */
-       list_for_each_entry(hwid, &adev->pnp.ids, list) {
-               if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
-                       acpi_of = true;
-                       break;
-               }
-       }
-
-       status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
-                                           ACPI_TYPE_PACKAGE);
-       if (ACPI_FAILURE(status))
-               goto out;
-
-       desc = buf.pointer;
        if (desc->package.count % 2)
-               goto fail;
+               return false;
 
        /* Look for the device properties UUID. */
        for (i = 0; i < desc->package.count; i += 2) {
@@ -154,18 +255,50 @@ void acpi_init_properties(struct acpi_device *adev)
                if (!acpi_properties_format_valid(properties))
                        break;
 
-               adev->data.pointer = buf.pointer;
-               adev->data.properties = properties;
+               data->properties = properties;
+               return true;
+       }
 
-               if (acpi_of)
-                       acpi_init_of_compatible(adev);
+       return false;
+}
 
+void acpi_init_properties(struct acpi_device *adev)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       struct acpi_hardware_id *hwid;
+       acpi_status status;
+       bool acpi_of = false;
+
+       INIT_LIST_HEAD(&adev->data.subnodes);
+
+       /*
+        * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
+        * Device Tree compatible properties for this device.
+        */
+       list_for_each_entry(hwid, &adev->pnp.ids, list) {
+               if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
+                       acpi_of = true;
+                       break;
+               }
+       }
+
+       status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+                                           ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status))
                goto out;
+
+       if (acpi_extract_properties(buf.pointer, &adev->data)) {
+               adev->data.pointer = buf.pointer;
+               if (acpi_of)
+                       acpi_init_of_compatible(adev);
        }
+       if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data))
+               adev->data.pointer = buf.pointer;
 
- fail:
-       dev_dbg(&adev->dev, "Returned _DSD data is not valid, skipping\n");
-       ACPI_FREE(buf.pointer);
+       if (!adev->data.pointer) {
+               acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n");
+               ACPI_FREE(buf.pointer);
+       }
 
  out:
        if (acpi_of && !adev->flags.of_compatible_ok)
@@ -173,8 +306,25 @@ void acpi_init_properties(struct acpi_device *adev)
                         ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
 }
 
+static void acpi_destroy_nondev_subnodes(struct list_head *list)
+{
+       struct acpi_data_node *dn, *next;
+
+       if (list_empty(list))
+               return;
+
+       list_for_each_entry_safe_reverse(dn, next, list, sibling) {
+               acpi_destroy_nondev_subnodes(&dn->data.subnodes);
+               wait_for_completion(&dn->kobj_done);
+               list_del(&dn->sibling);
+               ACPI_FREE((void *)dn->data.pointer);
+               kfree(dn);
+       }
+}
+
 void acpi_free_properties(struct acpi_device *adev)
 {
+       acpi_destroy_nondev_subnodes(&adev->data.subnodes);
        ACPI_FREE((void *)adev->data.pointer);
        adev->data.of_compatible = NULL;
        adev->data.pointer = NULL;
@@ -182,8 +332,8 @@ void acpi_free_properties(struct acpi_device *adev)
 }
 
 /**
- * acpi_dev_get_property - return an ACPI property with given name
- * @adev: ACPI device to get property
+ * acpi_data_get_property - return an ACPI property with given name
+ * @data: ACPI device deta object to get the property from
  * @name: Name of the property
  * @type: Expected property type
  * @obj: Location to store the property value (if not %NULL)
@@ -192,26 +342,27 @@ void acpi_free_properties(struct acpi_device *adev)
  * object at the location pointed to by @obj if found.
  *
  * Callers must not attempt to free the returned objects.  These objects will be
- * freed by the ACPI core automatically during the removal of @adev.
+ * freed by the ACPI core automatically during the removal of @data.
  *
  * Return: %0 if property with @name has been found (success),
  *         %-EINVAL if the arguments are invalid,
  *         %-ENODATA if the property doesn't exist,
  *         %-EPROTO if the property value type doesn't match @type.
  */
-int acpi_dev_get_property(struct acpi_device *adev, const char *name,
-                         acpi_object_type type, const union acpi_object **obj)
+static int acpi_data_get_property(struct acpi_device_data *data,
+                                 const char *name, acpi_object_type type,
+                                 const union acpi_object **obj)
 {
        const union acpi_object *properties;
        int i;
 
-       if (!adev || !name)
+       if (!data || !name)
                return -EINVAL;
 
-       if (!adev->data.pointer || !adev->data.properties)
+       if (!data->pointer || !data->properties)
                return -ENODATA;
 
-       properties = adev->data.properties;
+       properties = data->properties;
        for (i = 0; i < properties->package.count; i++) {
                const union acpi_object *propname, *propvalue;
                const union acpi_object *property;
@@ -232,11 +383,50 @@ int acpi_dev_get_property(struct acpi_device *adev, const char *name,
        }
        return -ENODATA;
 }
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name.
+ * @adev: ACPI device to get the property from.
+ * @name: Name of the property.
+ * @type: Expected property type.
+ * @obj: Location to store the property value (if not %NULL).
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+                         acpi_object_type type, const union acpi_object **obj)
+{
+       return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL;
+}
 EXPORT_SYMBOL_GPL(acpi_dev_get_property);
 
+static struct acpi_device_data *acpi_device_data_of_node(struct fwnode_handle *fwnode)
+{
+       if (fwnode->type == FWNODE_ACPI) {
+               struct acpi_device *adev = to_acpi_device_node(fwnode);
+               return &adev->data;
+       } else if (fwnode->type == FWNODE_ACPI_DATA) {
+               struct acpi_data_node *dn = to_acpi_data_node(fwnode);
+               return &dn->data;
+       }
+       return NULL;
+}
+
+/**
+ * acpi_node_prop_get - return an ACPI property with given name.
+ * @fwnode: Firmware node to get the property from.
+ * @propname: Name of the property.
+ * @valptr: Location to store a pointer to the property value (if not %NULL).
+ */
+int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
+                      void **valptr)
+{
+       return acpi_data_get_property(acpi_device_data_of_node(fwnode),
+                                     propname, ACPI_TYPE_ANY,
+                                     (const union acpi_object **)valptr);
+}
+
 /**
- * acpi_dev_get_property_array - return an ACPI array property with given name
- * @adev: ACPI device to get property
+ * acpi_data_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI data object to get the property from
  * @name: Name of the property
  * @type: Expected type of array elements
  * @obj: Location to store a pointer to the property value (if not NULL)
@@ -245,7 +435,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_get_property);
  * ACPI object at the location pointed to by @obj if found.
  *
  * Callers must not attempt to free the returned objects.  Those objects will be
- * freed by the ACPI core automatically during the removal of @adev.
+ * freed by the ACPI core automatically during the removal of @data.
  *
  * Return: %0 if array property (package) with @name has been found (success),
  *         %-EINVAL if the arguments are invalid,
@@ -253,14 +443,15 @@ EXPORT_SYMBOL_GPL(acpi_dev_get_property);
  *         %-EPROTO if the property is not a package or the type of its elements
  *           doesn't match @type.
  */
-int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
-                               acpi_object_type type,
-                               const union acpi_object **obj)
+static int acpi_data_get_property_array(struct acpi_device_data *data,
+                                       const char *name,
+                                       acpi_object_type type,
+                                       const union acpi_object **obj)
 {
        const union acpi_object *prop;
        int ret, i;
 
-       ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+       ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop);
        if (ret)
                return ret;
 
@@ -275,12 +466,11 @@ int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
 
 /**
- * acpi_dev_get_property_reference - returns handle to the referenced object
- * @adev: ACPI device to get property
- * @name: Name of the property
+ * acpi_data_get_property_reference - returns handle to the referenced object
+ * @data: ACPI device data object containing the property
+ * @propname: Name of the property
  * @index: Index of the reference to return
  * @args: Location to store the returned reference with optional arguments
  *
@@ -294,16 +484,16 @@ EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
  *
  * Return: %0 on success, negative error code on failure.
  */
-int acpi_dev_get_property_reference(struct acpi_device *adev,
-                                   const char *name, size_t index,
-                                   struct acpi_reference_args *args)
+static int acpi_data_get_property_reference(struct acpi_device_data *data,
+                                           const char *propname, size_t index,
+                                           struct acpi_reference_args *args)
 {
        const union acpi_object *element, *end;
        const union acpi_object *obj;
        struct acpi_device *device;
        int ret, idx = 0;
 
-       ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+       ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
        if (ret)
                return ret;
 
@@ -378,17 +568,27 @@ int acpi_dev_get_property_reference(struct acpi_device *adev,
 
        return -EPROTO;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
 
-int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
-                     void **valptr)
+/**
+ * acpi_node_get_property_reference - get a handle to the referenced object.
+ * @fwnode: Firmware node to get the property from.
+ * @propname: Name of the property.
+ * @index: Index of the reference to return.
+ * @args: Location to store the returned reference with optional arguments.
+ */
+int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
+                                    const char *name, size_t index,
+                                    struct acpi_reference_args *args)
 {
-       return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
-                                    (const union acpi_object **)valptr);
+       struct acpi_device_data *data = acpi_device_data_of_node(fwnode);
+
+       return data ? acpi_data_get_property_reference(data, name, index, args) : -EINVAL;
 }
+EXPORT_SYMBOL_GPL(acpi_node_get_property_reference);
 
-int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
-                             enum dev_prop_type proptype, void *val)
+static int acpi_data_prop_read_single(struct acpi_device_data *data,
+                                     const char *propname,
+                                     enum dev_prop_type proptype, void *val)
 {
        const union acpi_object *obj;
        int ret;
@@ -397,7 +597,7 @@ int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
                return -EINVAL;
 
        if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
-               ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+               ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
                if (ret)
                        return ret;
 
@@ -422,7 +622,7 @@ int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
                        break;
                }
        } else if (proptype == DEV_PROP_STRING) {
-               ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+               ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
                if (ret)
                        return ret;
 
@@ -433,6 +633,12 @@ int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
        return ret;
 }
 
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+                             enum dev_prop_type proptype, void *val)
+{
+       return adev ? acpi_data_prop_read_single(&adev->data, propname, proptype, val) : -EINVAL;
+}
+
 static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
                                       size_t nval)
 {
@@ -509,20 +715,22 @@ static int acpi_copy_property_array_string(const union acpi_object *items,
        return 0;
 }
 
-int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
-                      enum dev_prop_type proptype, void *val, size_t nval)
+static int acpi_data_prop_read(struct acpi_device_data *data,
+                              const char *propname,
+                              enum dev_prop_type proptype,
+                              void *val, size_t nval)
 {
        const union acpi_object *obj;
        const union acpi_object *items;
        int ret;
 
        if (val && nval == 1) {
-               ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
+               ret = acpi_data_prop_read_single(data, propname, proptype, val);
                if (!ret)
                        return ret;
        }
 
-       ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+       ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
        if (ret)
                return ret;
 
@@ -558,3 +766,84 @@ int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
        }
        return ret;
 }
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+                      enum dev_prop_type proptype, void *val, size_t nval)
+{
+       return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;
+}
+
+/**
+ * acpi_node_prop_read - retrieve the value of an ACPI property with given name.
+ * @fwnode: Firmware node to get the property from.
+ * @propname: Name of the property.
+ * @proptype: Expected property type.
+ * @val: Location to store the property value (if not %NULL).
+ * @nval: Size of the array pointed to by @val.
+ *
+ * If @val is %NULL, return the number of array elements comprising the value
+ * of the property.  Otherwise, read at most @nval values to the array at the
+ * location pointed to by @val.
+ */
+int acpi_node_prop_read(struct fwnode_handle *fwnode,  const char *propname,
+                       enum dev_prop_type proptype, void *val, size_t nval)
+{
+       return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
+                                  propname, proptype, val, nval);
+}
+
+/**
+ * acpi_get_next_subnode - Return the next child node handle for a device.
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+                                           struct fwnode_handle *child)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct list_head *head, *next;
+
+       if (!adev)
+               return NULL;
+
+       if (!child || child->type == FWNODE_ACPI) {
+               head = &adev->children;
+               if (list_empty(head))
+                       goto nondev;
+
+               if (child) {
+                       adev = to_acpi_device_node(child);
+                       next = adev->node.next;
+                       if (next == head) {
+                               child = NULL;
+                               goto nondev;
+                       }
+                       adev = list_entry(next, struct acpi_device, node);
+               } else {
+                       adev = list_first_entry(head, struct acpi_device, node);
+               }
+               return acpi_fwnode_handle(adev);
+       }
+
+ nondev:
+       if (!child || child->type == FWNODE_ACPI_DATA) {
+               struct acpi_data_node *dn;
+
+               head = &adev->data.subnodes;
+               if (list_empty(head))
+                       return NULL;
+
+               if (child) {
+                       dn = to_acpi_data_node(child);
+                       next = dn->sibling.next;
+                       if (next == head)
+                               return NULL;
+
+                       dn = list_entry(next, struct acpi_data_node, sibling);
+               } else {
+                       dn = list_first_entry(head, struct acpi_data_node, sibling);
+               }
+               return &dn->fwnode;
+       }
+       return NULL;
+}
index 15d22db05054526a95c233ea7f9de1c5510c4b42..cdc5c2599bebcc1a95ca2f29a525a5e63fab3b0f 100644 (file)
@@ -119,7 +119,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
 EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
 
 static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
-                                     u8 io_decode)
+                                     u8 io_decode, u8 translation_type)
 {
        res->flags = IORESOURCE_IO;
 
@@ -131,6 +131,8 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
 
        if (io_decode == ACPI_DECODE_16)
                res->flags |= IORESOURCE_IO_16BIT_ADDR;
+       if (translation_type == ACPI_SPARSE_TRANSLATION)
+               res->flags |= IORESOURCE_IO_SPARSE;
 }
 
 static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
@@ -138,7 +140,7 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
 {
        res->start = start;
        res->end = start + len - 1;
-       acpi_dev_ioresource_flags(res, len, io_decode);
+       acpi_dev_ioresource_flags(res, len, io_decode, 0);
 }
 
 /**
@@ -231,7 +233,8 @@ static bool acpi_decode_space(struct resource_win *win,
                acpi_dev_memresource_flags(res, len, wp);
                break;
        case ACPI_IO_RANGE:
-               acpi_dev_ioresource_flags(res, len, iodec);
+               acpi_dev_ioresource_flags(res, len, iodec,
+                                         addr->info.io.translation_type);
                break;
        case ACPI_BUS_NUMBER_RANGE:
                res->flags = IORESOURCE_BUS;
index 01136b8790381ccff5afc259e47643c338914740..daf9fc8329e64c41817269d0b6c437e3ccb2d1e3 100644 (file)
@@ -695,26 +695,6 @@ int acpi_device_add(struct acpi_device *device,
        return result;
 }
 
-struct acpi_device *acpi_get_next_child(struct device *dev,
-                                       struct acpi_device *child)
-{
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       struct list_head *head, *next;
-
-       if (!adev)
-               return NULL;
-
-       head = &adev->children;
-       if (list_empty(head))
-               return NULL;
-
-       if (!child)
-               return list_first_entry(head, struct acpi_device, node);
-
-       next = child->node.next;
-       return next == head ? NULL : list_entry(next, struct acpi_device, node);
-}
-
 /* --------------------------------------------------------------------------
                                  Device Enumeration
    -------------------------------------------------------------------------- */
@@ -1184,7 +1164,7 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
        if (!id)
                return;
 
-       id->id = kstrdup(dev_id, GFP_KERNEL);
+       id->id = kstrdup_const(dev_id, GFP_KERNEL);
        if (!id->id) {
                kfree(id);
                return;
@@ -1322,7 +1302,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
        struct acpi_hardware_id *id, *tmp;
 
        list_for_each_entry_safe(id, tmp, &pnp->ids, list) {
-               kfree(id->id);
+               kfree_const(id->id);
                kfree(id);
        }
        kfree(pnp->unique_id);
@@ -1472,7 +1452,7 @@ bool acpi_device_is_present(struct acpi_device *adev)
 }
 
 static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
-                                      char *idstr,
+                                      const char *idstr,
                                       const struct acpi_device_id **matchid)
 {
        const struct acpi_device_id *devid;
@@ -1491,7 +1471,7 @@ static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
        return false;
 }
 
-static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
+static struct acpi_scan_handler *acpi_scan_match_handler(const char *idstr,
                                        const struct acpi_device_id **matchid)
 {
        struct acpi_scan_handler *handler;
@@ -1933,3 +1913,42 @@ int __init acpi_scan_init(void)
        mutex_unlock(&acpi_scan_lock);
        return result;
 }
+
+static struct acpi_probe_entry *ape;
+static int acpi_probe_count;
+static DEFINE_SPINLOCK(acpi_probe_lock);
+
+static int __init acpi_match_madt(struct acpi_subtable_header *header,
+                                 const unsigned long end)
+{
+       if (!ape->subtable_valid || ape->subtable_valid(header, ape))
+               if (!ape->probe_subtbl(header, end))
+                       acpi_probe_count++;
+
+       return 0;
+}
+
+int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
+{
+       int count = 0;
+
+       if (acpi_disabled)
+               return 0;
+
+       spin_lock(&acpi_probe_lock);
+       for (ape = ap_head; nr; ape++, nr--) {
+               if (ACPI_COMPARE_NAME(ACPI_SIG_MADT, ape->id)) {
+                       acpi_probe_count = 0;
+                       acpi_table_parse_madt(ape->type, acpi_match_madt, 0);
+                       count += acpi_probe_count;
+               } else {
+                       int res;
+                       res = acpi_table_parse(ape->id, ape->probe_table);
+                       if (!res)
+                               count++;
+               }
+       }
+       spin_unlock(&acpi_probe_lock);
+
+       return count;
+}
index 2f0d4db40a9e8aa078787b177d138322fdd6c0b9..0d94621dc856080a0a3715040b7b5339c1edb248 100644 (file)
@@ -487,6 +487,8 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
                pr_err("ACPI does not support sleep state S%u\n", acpi_state);
                return -ENOSYS;
        }
+       if (acpi_state > ACPI_STATE_S1)
+               pm_set_suspend_via_firmware();
 
        acpi_pm_start(acpi_state);
        return 0;
@@ -522,6 +524,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                if (error)
                        return error;
                pr_info(PREFIX "Low-level resume complete\n");
+               pm_set_resume_via_firmware();
                break;
        }
        trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
@@ -632,14 +635,16 @@ 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);
+       if (acpi_sci_irq_valid())
+               enable_irq_wake(acpi_sci_irq);
        return 0;
 }
 
 static void acpi_freeze_restore(void)
 {
        acpi_disable_wakeup_devices(ACPI_STATE_S0);
-       disable_irq_wake(acpi_gbl_FADT.sci_interrupt);
+       if (acpi_sci_irq_valid())
+               disable_irq_wake(acpi_sci_irq);
        acpi_enable_all_runtime_gpes();
 }
 
index 40a42655227c2ccacd6cf0c0f47269224a8fe658..0243d375c6fd40134bd7404008ef6e43144867dc 100644 (file)
@@ -878,6 +878,9 @@ int __init acpi_sysfs_init(void)
                return result;
 
        hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
+       if (!hotplug_kobj)
+               return -ENOMEM;
+
        result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr);
        if (result)
                return result;
index 17a6fa01a3384e3d1ab52bbb585c50b7f4bde990..6c0f0794aa82bd007a14effaa21494043e3eb8e1 100644 (file)
@@ -210,20 +210,39 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
        }
 }
 
-int __init
-acpi_parse_entries(char *id, unsigned long table_size,
-               acpi_tbl_entry_handler handler,
+/**
+ * acpi_parse_entries_array - for each proc_num find a suitable subtable
+ *
+ * @id: table id (for debugging purposes)
+ * @table_size: single entry size
+ * @table_header: where does the table start?
+ * @proc: array of acpi_subtable_proc struct containing entry id
+ *        and associated handler with it
+ * @proc_num: how big proc is?
+ * @max_entries: how many entries can we process?
+ *
+ * For each proc_num find a subtable with proc->id and run proc->handler
+ * on it. Assumption is that there's only single handler for particular
+ * entry id.
+ *
+ * On success returns sum of all matching entries for all proc handlers.
+ * Otherwise, -ENODEV or -EINVAL is returned.
+ */
+static int __init
+acpi_parse_entries_array(char *id, unsigned long table_size,
                struct acpi_table_header *table_header,
-               int entry_id, unsigned int max_entries)
+               struct acpi_subtable_proc *proc, int proc_num,
+               unsigned int max_entries)
 {
        struct acpi_subtable_header *entry;
-       int count = 0;
        unsigned long table_end;
+       int count = 0;
+       int i;
 
        if (acpi_disabled)
                return -ENODEV;
 
-       if (!id || !handler)
+       if (!id)
                return -EINVAL;
 
        if (!table_size)
@@ -243,20 +262,28 @@ acpi_parse_entries(char *id, unsigned long table_size,
 
        while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
               table_end) {
-               if (entry->type == entry_id
-                   && (!max_entries || count < max_entries)) {
-                       if (handler(entry, table_end))
+               if (max_entries && count >= max_entries)
+                       break;
+
+               for (i = 0; i < proc_num; i++) {
+                       if (entry->type != proc[i].id)
+                               continue;
+                       if (!proc[i].handler ||
+                            proc[i].handler(entry, table_end))
                                return -EINVAL;
 
-                       count++;
+                       proc->count++;
+                       break;
                }
+               if (i != proc_num)
+                       count++;
 
                /*
                 * If entry->length is 0, break from this loop to avoid
                 * infinite loop.
                 */
                if (entry->length == 0) {
-                       pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
+                       pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
                        return -EINVAL;
                }
 
@@ -266,17 +293,32 @@ acpi_parse_entries(char *id, unsigned long table_size,
 
        if (max_entries && count > max_entries) {
                pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
-                       id, entry_id, count - max_entries, count);
+                       id, proc->id, count - max_entries, count);
        }
 
        return count;
 }
 
 int __init
-acpi_table_parse_entries(char *id,
+acpi_parse_entries(char *id,
+                       unsigned long table_size,
+                       acpi_tbl_entry_handler handler,
+                       struct acpi_table_header *table_header,
+                       int entry_id, unsigned int max_entries)
+{
+       struct acpi_subtable_proc proc = {
+               .id             = entry_id,
+               .handler        = handler,
+       };
+
+       return acpi_parse_entries_array(id, table_size, table_header,
+                       &proc, 1, max_entries);
+}
+
+int __init
+acpi_table_parse_entries_array(char *id,
                         unsigned long table_size,
-                        int entry_id,
-                        acpi_tbl_entry_handler handler,
+                        struct acpi_subtable_proc *proc, int proc_num,
                         unsigned int max_entries)
 {
        struct acpi_table_header *table_header = NULL;
@@ -287,7 +329,7 @@ acpi_table_parse_entries(char *id,
        if (acpi_disabled)
                return -ENODEV;
 
-       if (!id || !handler)
+       if (!id)
                return -EINVAL;
 
        if (!strncmp(id, ACPI_SIG_MADT, 4))
@@ -299,13 +341,29 @@ acpi_table_parse_entries(char *id,
                return -ENODEV;
        }
 
-       count = acpi_parse_entries(id, table_size, handler, table_header,
-                       entry_id, max_entries);
+       count = acpi_parse_entries_array(id, table_size, table_header,
+                       proc, proc_num, max_entries);
 
        early_acpi_os_unmap_memory((char *)table_header, tbl_size);
        return count;
 }
 
+int __init
+acpi_table_parse_entries(char *id,
+                       unsigned long table_size,
+                       int entry_id,
+                       acpi_tbl_entry_handler handler,
+                       unsigned int max_entries)
+{
+       struct acpi_subtable_proc proc = {
+               .id             = entry_id,
+               .handler        = handler,
+       };
+
+       return acpi_table_parse_entries_array(id, table_size, &proc, 1,
+                                               max_entries);
+}
+
 int __init
 acpi_table_parse_madt(enum acpi_madt_type id,
                      acpi_tbl_entry_handler handler, unsigned int max_entries)
index 2922f1f252d58aafd2d6c233404ae7ca21abb524..0d3a384b508a9c4782b7fe20ca1264dc3b11b0bf 100644 (file)
@@ -243,6 +243,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
 
        /* Non win8 machines which need native backlight nevertheless */
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1201530 */
+        .callback = video_detect_force_native,
+        .ident = "Lenovo Ideapad S405",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"),
+               },
+       },
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
         .callback = video_detect_force_native,
index f94a6ccfe78710bb386ca17d8032f9b9f2a5dd7f..5998c53280f547cc5854a6449d41ccb95fa99c75 100644 (file)
@@ -1,7 +1,7 @@
 obj-$(CONFIG_PM)       += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
 obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
-obj-$(CONFIG_PM_OPP)   += opp.o
+obj-$(CONFIG_PM_OPP)   += opp/
 obj-$(CONFIG_PM_GENERIC_DOMAINS)       +=  domain.o domain_governor.o
 obj-$(CONFIG_HAVE_CLK) += clock_ops.o
 
index 6ce76934057fcc15831a85400754c551294b35d9..60ee5591ee8f0d58d8229bad412d0f5882064e6a 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/err.h>
 #include <linux/pm_runtime.h>
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_CLK
 
 enum pce_status {
        PCE_STATUS_NONE = 0,
@@ -406,7 +406,7 @@ int pm_clk_runtime_resume(struct device *dev)
        return pm_generic_runtime_resume(dev);
 }
 
-#else /* !CONFIG_PM */
+#else /* !CONFIG_PM_CLK */
 
 /**
  * enable_clock - Enable a device clock.
@@ -486,7 +486,7 @@ static int pm_clk_notify(struct notifier_block *nb,
        return 0;
 }
 
-#endif /* !CONFIG_PM */
+#endif /* !CONFIG_PM_CLK */
 
 /**
  * pm_clk_add_notifier - Add bus type notifier for power management clocks.
index 16550c63d611ad8e484ccdec663ca1cc7142e144..a7dfdf9f15bada9112d38c6c5616abbd40f3762c 100644 (file)
        __ret;                                                  \
 })
 
-#define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name)      \
-({                                                                             \
-       ktime_t __start = ktime_get();                                          \
-       type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev);         \
-       s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start));           \
-       struct gpd_timing_data *__td = &dev_gpd_data(dev)->td;                  \
-       if (!__retval && __elapsed > __td->field) {                             \
-               __td->field = __elapsed;                                        \
-               dev_dbg(dev, name " latency exceeded, new value %lld ns\n",     \
-                       __elapsed);                                             \
-               genpd->max_off_time_changed = true;                             \
-               __td->constraint_changed = true;                                \
-       }                                                                       \
-       __retval;                                                               \
-})
-
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
-static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
-{
-       struct generic_pm_domain *genpd = NULL, *gpd;
-
-       if (IS_ERR_OR_NULL(domain_name))
-               return NULL;
-
-       mutex_lock(&gpd_list_lock);
-       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
-               if (!strcmp(gpd->name, domain_name)) {
-                       genpd = gpd;
-                       break;
-               }
-       }
-       mutex_unlock(&gpd_list_lock);
-       return genpd;
-}
-
 /*
  * Get the generic PM domain for a particular struct device.
  * This validates the struct device pointer, the PM domain pointer,
@@ -110,18 +76,12 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
 
 static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
 {
-       return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev,
-                                       stop_latency_ns, "stop");
+       return GENPD_DEV_CALLBACK(genpd, int, stop, dev);
 }
 
-static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev,
-                       bool timed)
+static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
 {
-       if (!timed)
-               return GENPD_DEV_CALLBACK(genpd, int, start, dev);
-
-       return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev,
-                                       start_latency_ns, "start");
+       return GENPD_DEV_CALLBACK(genpd, int, start, dev);
 }
 
 static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
@@ -140,19 +100,6 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
        smp_mb__after_atomic();
 }
 
-static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
-{
-       s64 usecs64;
-
-       if (!genpd->cpuidle_data)
-               return;
-
-       usecs64 = genpd->power_on_latency_ns;
-       do_div(usecs64, NSEC_PER_USEC);
-       usecs64 += genpd->cpuidle_data->saved_exit_latency;
-       genpd->cpuidle_data->idle_state->exit_latency = usecs64;
-}
-
 static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
        ktime_t time_start;
@@ -176,7 +123,6 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 
        genpd->power_on_latency_ns = elapsed_ns;
        genpd->max_off_time_changed = true;
-       genpd_recalc_cpu_exit_latency(genpd);
        pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
                 genpd->name, "on", elapsed_ns);
 
@@ -213,10 +159,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 }
 
 /**
- * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff().
+ * genpd_queue_power_off_work - Queue up the execution of genpd_poweroff().
  * @genpd: PM domait to power off.
  *
- * Queue up the execution of pm_genpd_poweroff() unless it's already been done
+ * Queue up the execution of genpd_poweroff() unless it's already been done
  * before.
  */
 static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
@@ -224,14 +170,16 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
        queue_work(pm_wq, &genpd->power_off_work);
 }
 
+static int genpd_poweron(struct generic_pm_domain *genpd);
+
 /**
- * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
+ * __genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  *
  * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
-static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+static int __genpd_poweron(struct generic_pm_domain *genpd)
 {
        struct gpd_link *link;
        int ret = 0;
@@ -240,13 +188,6 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
            || (genpd->prepared_count > 0 && genpd->suspend_power_off))
                return 0;
 
-       if (genpd->cpuidle_data) {
-               cpuidle_pause_and_lock();
-               genpd->cpuidle_data->idle_state->disabled = true;
-               cpuidle_resume_and_unlock();
-               goto out;
-       }
-
        /*
         * The list is guaranteed not to change while the loop below is being
         * executed, unless one of the masters' .power_on() callbacks fiddles
@@ -255,7 +196,7 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
        list_for_each_entry(link, &genpd->slave_links, slave_node) {
                genpd_sd_counter_inc(link->master);
 
-               ret = pm_genpd_poweron(link->master);
+               ret = genpd_poweron(link->master);
                if (ret) {
                        genpd_sd_counter_dec(link->master);
                        goto err;
@@ -266,7 +207,6 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
        if (ret)
                goto err;
 
- out:
        genpd->status = GPD_STATE_ACTIVE;
        return 0;
 
@@ -282,46 +222,28 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its masters.
+ * genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  */
-int pm_genpd_poweron(struct generic_pm_domain *genpd)
+static int genpd_poweron(struct generic_pm_domain *genpd)
 {
        int ret;
 
        mutex_lock(&genpd->lock);
-       ret = __pm_genpd_poweron(genpd);
+       ret = __genpd_poweron(genpd);
        mutex_unlock(&genpd->lock);
        return ret;
 }
 
-/**
- * pm_genpd_name_poweron - Restore power to a given PM domain and its masters.
- * @domain_name: Name of the PM domain to power up.
- */
-int pm_genpd_name_poweron(const char *domain_name)
-{
-       struct generic_pm_domain *genpd;
-
-       genpd = pm_genpd_lookup_name(domain_name);
-       return genpd ? pm_genpd_poweron(genpd) : -EINVAL;
-}
-
 static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
 {
-       return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
-                                       save_state_latency_ns, "state save");
+       return GENPD_DEV_CALLBACK(genpd, int, save_state, dev);
 }
 
 static int genpd_restore_dev(struct generic_pm_domain *genpd,
-                       struct device *dev, bool timed)
+                       struct device *dev)
 {
-       if (!timed)
-               return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
-
-       return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
-                                       restore_state_latency_ns,
-                                       "state restore");
+       return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
 }
 
 static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
@@ -365,13 +287,14 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 }
 
 /**
- * pm_genpd_poweroff - Remove power from a given PM domain.
+ * genpd_poweroff - Remove power from a given PM domain.
  * @genpd: PM domain to power down.
+ * @is_async: PM domain is powered down from a scheduled work
  *
  * If all of the @genpd's devices have been suspended and all of its subdomains
  * have been powered down, remove power from @genpd.
  */
-static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
+static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
 {
        struct pm_domain_data *pdd;
        struct gpd_link *link;
@@ -403,7 +326,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
                        not_suspended++;
        }
 
-       if (not_suspended > genpd->in_progress)
+       if (not_suspended > 1 || (not_suspended == 1 && is_async))
                return -EBUSY;
 
        if (genpd->gov && genpd->gov->power_down_ok) {
@@ -411,21 +334,6 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
                        return -EAGAIN;
        }
 
-       if (genpd->cpuidle_data) {
-               /*
-                * If cpuidle_data is set, cpuidle should turn the domain off
-                * when the CPU in it is idle.  In that case we don't decrement
-                * the subdomain counts of the master domains, so that power is
-                * not removed from the current domain prematurely as a result
-                * of cutting off the masters' power.
-                */
-               genpd->status = GPD_STATE_POWER_OFF;
-               cpuidle_pause_and_lock();
-               genpd->cpuidle_data->idle_state->disabled = false;
-               cpuidle_resume_and_unlock();
-               return 0;
-       }
-
        if (genpd->power_off) {
                int ret;
 
@@ -434,10 +342,10 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
 
                /*
                 * If sd_count > 0 at this point, one of the subdomains hasn't
-                * managed to call pm_genpd_poweron() for the master yet after
-                * incrementing it.  In that case pm_genpd_poweron() will wait
+                * managed to call genpd_poweron() for the master yet after
+                * incrementing it.  In that case genpd_poweron() will wait
                 * for us to drop the lock, so we can call .power_off() and let
-                * the pm_genpd_poweron() restore power for us (this shouldn't
+                * the genpd_poweron() restore power for us (this shouldn't
                 * happen very often).
                 */
                ret = genpd_power_off(genpd, true);
@@ -466,7 +374,7 @@ static void genpd_power_off_work_fn(struct work_struct *work)
        genpd = container_of(work, struct generic_pm_domain, power_off_work);
 
        mutex_lock(&genpd->lock);
-       pm_genpd_poweroff(genpd);
+       genpd_poweroff(genpd, true);
        mutex_unlock(&genpd->lock);
 }
 
@@ -482,6 +390,9 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        bool (*stop_ok)(struct device *__dev);
+       struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       ktime_t time_start;
+       s64 elapsed_ns;
        int ret;
 
        dev_dbg(dev, "%s()\n", __func__);
@@ -494,16 +405,29 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        if (stop_ok && !stop_ok(dev))
                return -EBUSY;
 
+       /* Measure suspend latency. */
+       time_start = ktime_get();
+
        ret = genpd_save_dev(genpd, dev);
        if (ret)
                return ret;
 
        ret = genpd_stop_dev(genpd, dev);
        if (ret) {
-               genpd_restore_dev(genpd, dev, true);
+               genpd_restore_dev(genpd, dev);
                return ret;
        }
 
+       /* Update suspend latency value if the measured time exceeds it. */
+       elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+       if (elapsed_ns > td->suspend_latency_ns) {
+               td->suspend_latency_ns = elapsed_ns;
+               dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
+                       elapsed_ns);
+               genpd->max_off_time_changed = true;
+               td->constraint_changed = true;
+       }
+
        /*
         * If power.irq_safe is set, this routine will be run with interrupts
         * off, so it can't use mutexes.
@@ -512,9 +436,7 @@ static int pm_genpd_runtime_suspend(struct device *dev)
                return 0;
 
        mutex_lock(&genpd->lock);
-       genpd->in_progress++;
-       pm_genpd_poweroff(genpd);
-       genpd->in_progress--;
+       genpd_poweroff(genpd, false);
        mutex_unlock(&genpd->lock);
 
        return 0;
@@ -531,6 +453,9 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 static int pm_genpd_runtime_resume(struct device *dev)
 {
        struct generic_pm_domain *genpd;
+       struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       ktime_t time_start;
+       s64 elapsed_ns;
        int ret;
        bool timed = true;
 
@@ -547,15 +472,31 @@ static int pm_genpd_runtime_resume(struct device *dev)
        }
 
        mutex_lock(&genpd->lock);
-       ret = __pm_genpd_poweron(genpd);
+       ret = __genpd_poweron(genpd);
        mutex_unlock(&genpd->lock);
 
        if (ret)
                return ret;
 
  out:
-       genpd_start_dev(genpd, dev, timed);
-       genpd_restore_dev(genpd, dev, timed);
+       /* Measure resume latency. */
+       if (timed)
+               time_start = ktime_get();
+
+       genpd_start_dev(genpd, dev);
+       genpd_restore_dev(genpd, dev);
+
+       /* Update resume latency value if the measured time exceeds it. */
+       if (timed) {
+               elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+               if (elapsed_ns > td->resume_latency_ns) {
+                       td->resume_latency_ns = elapsed_ns;
+                       dev_dbg(dev, "resume latency exceeded, %lld ns\n",
+                               elapsed_ns);
+                       genpd->max_off_time_changed = true;
+                       td->constraint_changed = true;
+               }
+       }
 
        return 0;
 }
@@ -569,15 +510,15 @@ static int __init pd_ignore_unused_setup(char *__unused)
 __setup("pd_ignore_unused", pd_ignore_unused_setup);
 
 /**
- * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
+ * genpd_poweroff_unused - Power off all PM domains with no devices in use.
  */
-void pm_genpd_poweroff_unused(void)
+static int __init genpd_poweroff_unused(void)
 {
        struct generic_pm_domain *genpd;
 
        if (pd_ignore_unused) {
                pr_warn("genpd: Not disabling unused power domains\n");
-               return;
+               return 0;
        }
 
        mutex_lock(&gpd_list_lock);
@@ -586,11 +527,7 @@ void pm_genpd_poweroff_unused(void)
                genpd_queue_power_off_work(genpd);
 
        mutex_unlock(&gpd_list_lock);
-}
 
-static int __init genpd_poweroff_unused(void)
-{
-       pm_genpd_poweroff_unused();
        return 0;
 }
 late_initcall(genpd_poweroff_unused);
@@ -764,7 +701,7 @@ static int pm_genpd_prepare(struct device *dev)
 
        /*
         * The PM domain must be in the GPD_STATE_ACTIVE state at this point,
-        * so pm_genpd_poweron() will return immediately, but if the device
+        * so genpd_poweron() will return immediately, but if the device
         * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need
         * to make it operational.
         */
@@ -890,7 +827,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
        pm_genpd_sync_poweron(genpd, true);
        genpd->suspended_count--;
 
-       return genpd_start_dev(genpd, dev, true);
+       return genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1018,7 +955,8 @@ static int pm_genpd_thaw_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev, true);
+       return genpd->suspend_power_off ?
+               0 : genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1112,7 +1050,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
 
        pm_genpd_sync_poweron(genpd, true);
 
-       return genpd_start_dev(genpd, dev, true);
+       return genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1316,18 +1254,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        return ret;
 }
 
-/**
- * __pm_genpd_name_add_device - Find I/O PM domain and add a device to it.
- * @domain_name: Name of the PM domain to add the device to.
- * @dev: Device to be added.
- * @td: Set of PM QoS timing parameters to attach to the device.
- */
-int __pm_genpd_name_add_device(const char *domain_name, struct device *dev,
-                              struct gpd_timing_data *td)
-{
-       return __pm_genpd_add_device(pm_genpd_lookup_name(domain_name), dev, td);
-}
-
 /**
  * pm_genpd_remove_device - Remove a device from an I/O PM domain.
  * @genpd: PM domain to remove the device from.
@@ -1428,35 +1354,6 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
        return ret;
 }
 
-/**
- * pm_genpd_add_subdomain_names - Add a subdomain to an I/O PM domain.
- * @master_name: Name of the master PM domain to add the subdomain to.
- * @subdomain_name: Name of the subdomain to be added.
- */
-int pm_genpd_add_subdomain_names(const char *master_name,
-                                const char *subdomain_name)
-{
-       struct generic_pm_domain *master = NULL, *subdomain = NULL, *gpd;
-
-       if (IS_ERR_OR_NULL(master_name) || IS_ERR_OR_NULL(subdomain_name))
-               return -EINVAL;
-
-       mutex_lock(&gpd_list_lock);
-       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
-               if (!master && !strcmp(gpd->name, master_name))
-                       master = gpd;
-
-               if (!subdomain && !strcmp(gpd->name, subdomain_name))
-                       subdomain = gpd;
-
-               if (master && subdomain)
-                       break;
-       }
-       mutex_unlock(&gpd_list_lock);
-
-       return pm_genpd_add_subdomain(master, subdomain);
-}
-
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
@@ -1504,124 +1401,6 @@ out:
        return ret;
 }
 
-/**
- * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle.
- * @genpd: PM domain to be connected with cpuidle.
- * @state: cpuidle state this domain can disable/enable.
- *
- * Make a PM domain behave as though it contained a CPU core, that is, instead
- * of calling its power down routine it will enable the given cpuidle state so
- * that the cpuidle subsystem can power it down (if possible and desirable).
- */
-int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
-{
-       struct cpuidle_driver *cpuidle_drv;
-       struct gpd_cpuidle_data *cpuidle_data;
-       struct cpuidle_state *idle_state;
-       int ret = 0;
-
-       if (IS_ERR_OR_NULL(genpd) || state < 0)
-               return -EINVAL;
-
-       mutex_lock(&genpd->lock);
-
-       if (genpd->cpuidle_data) {
-               ret = -EEXIST;
-               goto out;
-       }
-       cpuidle_data = kzalloc(sizeof(*cpuidle_data), GFP_KERNEL);
-       if (!cpuidle_data) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       cpuidle_drv = cpuidle_driver_ref();
-       if (!cpuidle_drv) {
-               ret = -ENODEV;
-               goto err_drv;
-       }
-       if (cpuidle_drv->state_count <= state) {
-               ret = -EINVAL;
-               goto err;
-       }
-       idle_state = &cpuidle_drv->states[state];
-       if (!idle_state->disabled) {
-               ret = -EAGAIN;
-               goto err;
-       }
-       cpuidle_data->idle_state = idle_state;
-       cpuidle_data->saved_exit_latency = idle_state->exit_latency;
-       genpd->cpuidle_data = cpuidle_data;
-       genpd_recalc_cpu_exit_latency(genpd);
-
- out:
-       mutex_unlock(&genpd->lock);
-       return ret;
-
- err:
-       cpuidle_driver_unref();
-
- err_drv:
-       kfree(cpuidle_data);
-       goto out;
-}
-
-/**
- * pm_genpd_name_attach_cpuidle - Find PM domain and connect cpuidle to it.
- * @name: Name of the domain to connect to cpuidle.
- * @state: cpuidle state this domain can manipulate.
- */
-int pm_genpd_name_attach_cpuidle(const char *name, int state)
-{
-       return pm_genpd_attach_cpuidle(pm_genpd_lookup_name(name), state);
-}
-
-/**
- * pm_genpd_detach_cpuidle - Remove the cpuidle connection from a PM domain.
- * @genpd: PM domain to remove the cpuidle connection from.
- *
- * Remove the cpuidle connection set up by pm_genpd_attach_cpuidle() from the
- * given PM domain.
- */
-int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
-{
-       struct gpd_cpuidle_data *cpuidle_data;
-       struct cpuidle_state *idle_state;
-       int ret = 0;
-
-       if (IS_ERR_OR_NULL(genpd))
-               return -EINVAL;
-
-       mutex_lock(&genpd->lock);
-
-       cpuidle_data = genpd->cpuidle_data;
-       if (!cpuidle_data) {
-               ret = -ENODEV;
-               goto out;
-       }
-       idle_state = cpuidle_data->idle_state;
-       if (!idle_state->disabled) {
-               ret = -EAGAIN;
-               goto out;
-       }
-       idle_state->exit_latency = cpuidle_data->saved_exit_latency;
-       cpuidle_driver_unref();
-       genpd->cpuidle_data = NULL;
-       kfree(cpuidle_data);
-
- out:
-       mutex_unlock(&genpd->lock);
-       return ret;
-}
-
-/**
- * pm_genpd_name_detach_cpuidle - Find PM domain and disconnect cpuidle from it.
- * @name: Name of the domain to disconnect cpuidle from.
- */
-int pm_genpd_name_detach_cpuidle(const char *name)
-{
-       return pm_genpd_detach_cpuidle(pm_genpd_lookup_name(name));
-}
-
 /* Default device callbacks for generic PM domains. */
 
 /**
@@ -1688,7 +1467,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        mutex_init(&genpd->lock);
        genpd->gov = gov;
        INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
-       genpd->in_progress = 0;
        atomic_set(&genpd->sd_count, 0);
        genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
        genpd->device_count = 0;
@@ -2023,7 +1801,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;
-       ret = pm_genpd_poweron(pd);
+       ret = genpd_poweron(pd);
 
 out:
        return ret ? -EPROBE_DEFER : 0;
index 85e17bacc834156664c5980c4f7ea7ef68e5d6b6..e60dd12e23aaee75a2a0d90ba0ba720c28c769e7 100644 (file)
@@ -77,10 +77,8 @@ static bool default_stop_ok(struct device *dev)
                                      dev_update_qos_constraint);
 
        if (constraint_ns > 0) {
-               constraint_ns -= td->save_state_latency_ns +
-                               td->stop_latency_ns +
-                               td->start_latency_ns +
-                               td->restore_state_latency_ns;
+               constraint_ns -= td->suspend_latency_ns +
+                               td->resume_latency_ns;
                if (constraint_ns == 0)
                        return false;
        }
index 96a92db83cad863ac286ce2249b573bb7c1085a6..07c3c4a9522d4e6bec1f0f540bd38f8c1ce6ed00 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/export.h>
+#include <linux/suspend.h>
 
 #ifdef CONFIG_PM
 /**
@@ -296,11 +297,27 @@ void pm_generic_complete(struct device *dev)
 
        if (drv && drv->pm && drv->pm->complete)
                drv->pm->complete(dev);
+}
 
+/**
+ * pm_complete_with_resume_check - Complete a device power transition.
+ * @dev: Device to handle.
+ *
+ * Complete a device power transition during a system-wide power transition and
+ * optionally schedule a runtime resume of the device if the system resume in
+ * progress has been initated by the platform firmware and the device had its
+ * power.direct_complete flag set.
+ */
+void pm_complete_with_resume_check(struct device *dev)
+{
+       pm_generic_complete(dev);
        /*
-        * Let runtime PM try to suspend devices that haven't been in use before
-        * going into the system-wide sleep state we're resuming from.
+        * If the device had been runtime-suspended before the system went into
+        * the sleep state it is going out of and it has never been resumed till
+        * now, resume it in case the firmware powered it up.
         */
-       pm_request_idle(dev);
+       if (dev->power.direct_complete && pm_resume_via_firmware())
+               pm_request_resume(dev);
 }
+EXPORT_SYMBOL_GPL(pm_complete_with_resume_check);
 #endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/base/power/opp/Makefile b/drivers/base/power/opp/Makefile
new file mode 100644 (file)
index 0000000..33c1e18
--- /dev/null
@@ -0,0 +1,2 @@
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
+obj-y                          += core.o cpu.o
similarity index 79%
rename from drivers/base/power/opp.c
rename to drivers/base/power/opp/core.c
index 7ae7cd990fbf79bf39de570a6a0fca5bd47cef94..d5c1149ff123c335b58e1f8ee68ed97a66784fec 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/cpu.h>
-#include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/device.h>
-#include <linux/list.h>
-#include <linux/rculist.h>
-#include <linux/rcupdate.h>
-#include <linux/pm_opp.h>
 #include <linux/of.h>
 #include <linux/export.h>
 
-/*
- * Internal data structure organization with the OPP layer library is as
- * follows:
- * dev_opp_list (root)
- *     |- device 1 (represents voltage domain 1)
- *     |       |- opp 1 (availability, freq, voltage)
- *     |       |- opp 2 ..
- *     ...     ...
- *     |       `- opp n ..
- *     |- device 2 (represents the next voltage domain)
- *     ...
- *     `- device m (represents mth voltage domain)
- * device 1, 2.. are represented by dev_opp structure while each opp
- * is represented by the opp structure.
- */
-
-/**
- * struct dev_pm_opp - Generic OPP description structure
- * @node:      opp list node. The nodes are maintained throughout the lifetime
- *             of boot. It is expected only an optimal set of OPPs are
- *             added to the library by the SoC framework.
- *             RCU usage: opp list is traversed with RCU locks. node
- *             modification is possible realtime, hence the modifications
- *             are protected by the dev_opp_list_lock for integrity.
- *             IMPORTANT: the opp nodes should be maintained in increasing
- *             order.
- * @dynamic:   not-created from static DT entries.
- * @available: true/false - marks if this OPP as available or not
- * @turbo:     true if turbo (boost) OPP
- * @rate:      Frequency in hertz
- * @u_volt:    Target voltage in microvolts corresponding to this OPP
- * @u_volt_min:        Minimum voltage in microvolts corresponding to this OPP
- * @u_volt_max:        Maximum voltage in microvolts corresponding to this OPP
- * @u_amp:     Maximum current drawn by the device in microamperes
- * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
- *             frequency from any other OPP's frequency.
- * @dev_opp:   points back to the device_opp struct this opp belongs to
- * @rcu_head:  RCU callback head used for deferred freeing
- * @np:                OPP's device node.
- *
- * This structure stores the OPP information for a given device.
- */
-struct dev_pm_opp {
-       struct list_head node;
-
-       bool available;
-       bool dynamic;
-       bool turbo;
-       unsigned long rate;
-
-       unsigned long u_volt;
-       unsigned long u_volt_min;
-       unsigned long u_volt_max;
-       unsigned long u_amp;
-       unsigned long clock_latency_ns;
-
-       struct device_opp *dev_opp;
-       struct rcu_head rcu_head;
-
-       struct device_node *np;
-};
-
-/**
- * struct device_list_opp - devices managed by 'struct device_opp'
- * @node:      list node
- * @dev:       device to which the struct object belongs
- * @rcu_head:  RCU callback head used for deferred freeing
- *
- * This is an internal data structure maintaining the list of devices that are
- * managed by 'struct device_opp'.
- */
-struct device_list_opp {
-       struct list_head node;
-       const struct device *dev;
-       struct rcu_head rcu_head;
-};
-
-/**
- * struct device_opp - Device opp structure
- * @node:      list node - contains the devices with OPPs that
- *             have been registered. Nodes once added are not modified in this
- *             list.
- *             RCU usage: nodes are not modified in the list of device_opp,
- *             however addition is possible and is secured by dev_opp_list_lock
- * @srcu_head: notifier head to notify the OPP availability changes.
- * @rcu_head:  RCU callback head used for deferred freeing
- * @dev_list:  list of devices that share these OPPs
- * @opp_list:  list of opps
- * @np:                struct device_node pointer for opp's DT node.
- * @shared_opp: OPP is shared between multiple devices.
- *
- * This is an internal data structure maintaining the link to opps attached to
- * a device. This structure is not meant to be shared to users as it is
- * meant for book keeping and private to OPP library.
- *
- * Because the opp structures can be used from both rcu and srcu readers, we
- * need to wait for the grace period of both of them before freeing any
- * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
- */
-struct device_opp {
-       struct list_head node;
-
-       struct srcu_notifier_head srcu_head;
-       struct rcu_head rcu_head;
-       struct list_head dev_list;
-       struct list_head opp_list;
-
-       struct device_node *np;
-       unsigned long clock_latency_ns_max;
-       bool shared_opp;
-       struct dev_pm_opp *suspend_opp;
-};
+#include "opp.h"
 
 /*
  * The root of the list of all devices. All device_opp structures branch off
@@ -200,7 +83,7 @@ static struct device_opp *_managed_opp(const struct device_node *np)
  * is a RCU protected pointer. This means that device_opp is valid as long
  * as we are under RCU lock.
  */
-static struct device_opp *_find_device_opp(struct device *dev)
+struct device_opp *_find_device_opp(struct device *dev)
 {
        struct device_opp *dev_opp;
 
@@ -579,8 +462,8 @@ static void _remove_list_dev(struct device_list_opp *list_dev,
                  _kfree_list_dev_rcu);
 }
 
-static struct device_list_opp *_add_list_dev(const struct device *dev,
-                                            struct device_opp *dev_opp)
+struct device_list_opp *_add_list_dev(const struct device *dev,
+                                     struct device_opp *dev_opp)
 {
        struct device_list_opp *list_dev;
 
@@ -828,8 +711,8 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
  * The opp is made available by default and it can be controlled using
  * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove.
  *
- * NOTE: "dynamic" parameter impacts OPPs added by the of_init_opp_table and
- * freed by of_free_opp_table.
+ * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table
+ * and freed by dev_pm_opp_of_remove_table.
  *
  * Locking: The internal device_opp and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks
@@ -1220,7 +1103,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
 
 #ifdef CONFIG_OF
 /**
- * of_free_opp_table() - Free OPP table entries created from static DT entries
+ * dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT
+ *                               entries
  * @dev:       device pointer used to lookup device OPPs.
  *
  * Free OPPs created using static entries present in DT.
@@ -1231,7 +1115,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
  * that this function is *NOT* called under RCU protection or in contexts where
  * mutex cannot be locked.
  */
-void of_free_opp_table(struct device *dev)
+void dev_pm_opp_of_remove_table(struct device *dev)
 {
        struct device_opp *dev_opp;
        struct dev_pm_opp *opp, *tmp;
@@ -1266,91 +1150,34 @@ void of_free_opp_table(struct device *dev)
 unlock:
        mutex_unlock(&dev_opp_list_lock);
 }
-EXPORT_SYMBOL_GPL(of_free_opp_table);
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
 
-void of_cpumask_free_opp_table(cpumask_var_t cpumask)
+/* Returns opp descriptor node for a device, caller must do of_node_put() */
+struct device_node *_of_get_opp_desc_node(struct device *dev)
 {
-       struct device *cpu_dev;
-       int cpu;
-
-       WARN_ON(cpumask_empty(cpumask));
-
-       for_each_cpu(cpu, cpumask) {
-               cpu_dev = get_cpu_device(cpu);
-               if (!cpu_dev) {
-                       pr_err("%s: failed to get cpu%d device\n", __func__,
-                              cpu);
-                       continue;
-               }
-
-               of_free_opp_table(cpu_dev);
-       }
-}
-EXPORT_SYMBOL_GPL(of_cpumask_free_opp_table);
-
-/* Returns opp descriptor node from its phandle. Caller must do of_node_put() */
-static struct device_node *
-_of_get_opp_desc_node_from_prop(struct device *dev, const struct property *prop)
-{
-       struct device_node *opp_np;
-
-       opp_np = of_find_node_by_phandle(be32_to_cpup(prop->value));
-       if (!opp_np) {
-               dev_err(dev, "%s: Prop: %s contains invalid opp desc phandle\n",
-                       __func__, prop->name);
-               return ERR_PTR(-EINVAL);
-       }
-
-       return opp_np;
-}
-
-/* Returns opp descriptor node for a device. Caller must do of_node_put() */
-static struct device_node *_of_get_opp_desc_node(struct device *dev)
-{
-       const struct property *prop;
-
-       prop = of_find_property(dev->of_node, "operating-points-v2", NULL);
-       if (!prop)
-               return ERR_PTR(-ENODEV);
-       if (!prop->value)
-               return ERR_PTR(-ENODATA);
-
        /*
         * TODO: Support for multiple OPP tables.
         *
         * There should be only ONE phandle present in "operating-points-v2"
         * property.
         */
-       if (prop->length != sizeof(__be32)) {
-               dev_err(dev, "%s: Invalid opp desc phandle\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
 
-       return _of_get_opp_desc_node_from_prop(dev, prop);
+       return of_parse_phandle(dev->of_node, "operating-points-v2", 0);
 }
 
 /* Initializes OPP tables based on new bindings */
-static int _of_init_opp_table_v2(struct device *dev,
-                                const struct property *prop)
+static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
 {
-       struct device_node *opp_np, *np;
+       struct device_node *np;
        struct device_opp *dev_opp;
        int ret = 0, count = 0;
 
-       if (!prop->value)
-               return -ENODATA;
-
-       /* Get opp node */
-       opp_np = _of_get_opp_desc_node_from_prop(dev, prop);
-       if (IS_ERR(opp_np))
-               return PTR_ERR(opp_np);
-
        dev_opp = _managed_opp(opp_np);
        if (dev_opp) {
                /* OPPs are already managed */
                if (!_add_list_dev(dev, dev_opp))
                        ret = -ENOMEM;
-               goto put_opp_np;
+               return ret;
        }
 
        /* We have opp-list node now, iterate over it and add OPPs */
@@ -1366,10 +1193,8 @@ static int _of_init_opp_table_v2(struct device *dev,
        }
 
        /* There should be one of more OPP defined */
-       if (WARN_ON(!count)) {
-               ret = -ENOENT;
-               goto put_opp_np;
-       }
+       if (WARN_ON(!count))
+               return -ENOENT;
 
        dev_opp = _find_device_opp(dev);
        if (WARN_ON(IS_ERR(dev_opp))) {
@@ -1380,19 +1205,16 @@ static int _of_init_opp_table_v2(struct device *dev,
        dev_opp->np = opp_np;
        dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared");
 
-       of_node_put(opp_np);
        return 0;
 
 free_table:
-       of_free_opp_table(dev);
-put_opp_np:
-       of_node_put(opp_np);
+       dev_pm_opp_of_remove_table(dev);
 
        return ret;
 }
 
 /* Initializes OPP tables based on old-deprecated bindings */
-static int _of_init_opp_table_v1(struct device *dev)
+static int _of_add_opp_table_v1(struct device *dev)
 {
        const struct property *prop;
        const __be32 *val;
@@ -1429,7 +1251,7 @@ static int _of_init_opp_table_v1(struct device *dev)
 }
 
 /**
- * of_init_opp_table() - Initialize opp table from device tree
+ * dev_pm_opp_of_add_table() - Initialize opp table from device tree
  * @dev:       device pointer used to lookup device OPPs.
  *
  * Register the initial OPP table with the OPP library for given device.
@@ -1451,153 +1273,28 @@ static int _of_init_opp_table_v1(struct device *dev)
  * -ENODATA    when empty 'operating-points' property is found
  * -EINVAL     when invalid entries are found in opp-v2 table
  */
-int of_init_opp_table(struct device *dev)
+int dev_pm_opp_of_add_table(struct device *dev)
 {
-       const struct property *prop;
+       struct device_node *opp_np;
+       int ret;
 
        /*
         * OPPs have two version of bindings now. The older one is deprecated,
         * try for the new binding first.
         */
-       prop = of_find_property(dev->of_node, "operating-points-v2", NULL);
-       if (!prop) {
+       opp_np = _of_get_opp_desc_node(dev);
+       if (!opp_np) {
                /*
                 * Try old-deprecated bindings for backward compatibility with
                 * older dtbs.
                 */
-               return _of_init_opp_table_v1(dev);
-       }
-
-       return _of_init_opp_table_v2(dev, prop);
-}
-EXPORT_SYMBOL_GPL(of_init_opp_table);
-
-int of_cpumask_init_opp_table(cpumask_var_t cpumask)
-{
-       struct device *cpu_dev;
-       int cpu, ret = 0;
-
-       WARN_ON(cpumask_empty(cpumask));
-
-       for_each_cpu(cpu, cpumask) {
-               cpu_dev = get_cpu_device(cpu);
-               if (!cpu_dev) {
-                       pr_err("%s: failed to get cpu%d device\n", __func__,
-                              cpu);
-                       continue;
-               }
-
-               ret = of_init_opp_table(cpu_dev);
-               if (ret) {
-                       pr_err("%s: couldn't find opp table for cpu:%d, %d\n",
-                              __func__, cpu, ret);
-
-                       /* Free all other OPPs */
-                       of_cpumask_free_opp_table(cpumask);
-                       break;
-               }
+               return _of_add_opp_table_v1(dev);
        }
 
-       return ret;
-}
-EXPORT_SYMBOL_GPL(of_cpumask_init_opp_table);
-
-/* Required only for V1 bindings, as v2 can manage it from DT itself */
-int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask)
-{
-       struct device_list_opp *list_dev;
-       struct device_opp *dev_opp;
-       struct device *dev;
-       int cpu, ret = 0;
-
-       rcu_read_lock();
-
-       dev_opp = _find_device_opp(cpu_dev);
-       if (IS_ERR(dev_opp)) {
-               ret = -EINVAL;
-               goto out_rcu_read_unlock;
-       }
-
-       for_each_cpu(cpu, cpumask) {
-               if (cpu == cpu_dev->id)
-                       continue;
-
-               dev = get_cpu_device(cpu);
-               if (!dev) {
-                       dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
-                               __func__, cpu);
-                       continue;
-               }
-
-               list_dev = _add_list_dev(dev, dev_opp);
-               if (!list_dev) {
-                       dev_err(dev, "%s: failed to add list-dev for cpu%d device\n",
-                               __func__, cpu);
-                       continue;
-               }
-       }
-out_rcu_read_unlock:
-       rcu_read_unlock();
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(set_cpus_sharing_opps);
-
-/*
- * Works only for OPP v2 bindings.
- *
- * cpumask should be already set to mask of cpu_dev->id.
- * Returns -ENOENT if operating-points-v2 bindings aren't supported.
- */
-int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask)
-{
-       struct device_node *np, *tmp_np;
-       struct device *tcpu_dev;
-       int cpu, ret = 0;
-
-       /* Get OPP descriptor node */
-       np = _of_get_opp_desc_node(cpu_dev);
-       if (IS_ERR(np)) {
-               dev_dbg(cpu_dev, "%s: Couldn't find opp node: %ld\n", __func__,
-                       PTR_ERR(np));
-               return -ENOENT;
-       }
-
-       /* OPPs are shared ? */
-       if (!of_property_read_bool(np, "opp-shared"))
-               goto put_cpu_node;
-
-       for_each_possible_cpu(cpu) {
-               if (cpu == cpu_dev->id)
-                       continue;
-
-               tcpu_dev = get_cpu_device(cpu);
-               if (!tcpu_dev) {
-                       dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
-                               __func__, cpu);
-                       ret = -ENODEV;
-                       goto put_cpu_node;
-               }
-
-               /* Get OPP descriptor node */
-               tmp_np = _of_get_opp_desc_node(tcpu_dev);
-               if (IS_ERR(tmp_np)) {
-                       dev_err(tcpu_dev, "%s: Couldn't find opp node: %ld\n",
-                               __func__, PTR_ERR(tmp_np));
-                       ret = PTR_ERR(tmp_np);
-                       goto put_cpu_node;
-               }
-
-               /* CPUs are sharing opp node */
-               if (np == tmp_np)
-                       cpumask_set_cpu(cpu, cpumask);
-
-               of_node_put(tmp_np);
-       }
+       ret = _of_add_opp_table_v2(dev, opp_np);
+       of_node_put(opp_np);
 
-put_cpu_node:
-       of_node_put(np);
        return ret;
 }
-EXPORT_SYMBOL_GPL(of_get_cpus_sharing_opps);
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
 #endif
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c
new file mode 100644 (file)
index 0000000..7654c56
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Generic OPP helper interface for CPU device
+ *
+ * Copyright (C) 2009-2014 Texas Instruments Incorporated.
+ *     Nishanth Menon
+ *     Romit Dasgupta
+ *     Kevin Hilman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "opp.h"
+
+#ifdef CONFIG_CPU_FREQ
+
+/**
+ * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
+ * @dev:       device for which we do this operation
+ * @table:     Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided device- this assumes that the
+ * opp list is already initialized and ready for usage.
+ *
+ * This function allocates required memory for the cpufreq table. It is
+ * expected that the caller does the required maintenance such as freeing
+ * the table as required.
+ *
+ * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
+ * if no memory available for the operation (table is not populated), returns 0
+ * if successful and table is populated.
+ *
+ * WARNING: It is  important for the callers to ensure refreshing their copy of
+ * the table if any of the mentioned functions have been invoked in the interim.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Since we just use the regular accessor functions to access the internal data
+ * structures, we use RCU read lock inside this function. As a result, users of
+ * this function DONOT need to use explicit locks for invoking.
+ */
+int dev_pm_opp_init_cpufreq_table(struct device *dev,
+                                 struct cpufreq_frequency_table **table)
+{
+       struct dev_pm_opp *opp;
+       struct cpufreq_frequency_table *freq_table = NULL;
+       int i, max_opps, ret = 0;
+       unsigned long rate;
+
+       rcu_read_lock();
+
+       max_opps = dev_pm_opp_get_opp_count(dev);
+       if (max_opps <= 0) {
+               ret = max_opps ? max_opps : -ENODATA;
+               goto out;
+       }
+
+       freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
+       if (!freq_table) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0, rate = 0; i < max_opps; i++, rate++) {
+               /* find next rate */
+               opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+               if (IS_ERR(opp)) {
+                       ret = PTR_ERR(opp);
+                       goto out;
+               }
+               freq_table[i].driver_data = i;
+               freq_table[i].frequency = rate / 1000;
+
+               /* Is Boost/turbo opp ? */
+               if (dev_pm_opp_is_turbo(opp))
+                       freq_table[i].flags = CPUFREQ_BOOST_FREQ;
+       }
+
+       freq_table[i].driver_data = i;
+       freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+       *table = &freq_table[0];
+
+out:
+       rcu_read_unlock();
+       if (ret)
+               kfree(freq_table);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
+
+/**
+ * dev_pm_opp_free_cpufreq_table() - free the cpufreq table
+ * @dev:       device for which we do this operation
+ * @table:     table to free
+ *
+ * Free up the table allocated by dev_pm_opp_init_cpufreq_table
+ */
+void dev_pm_opp_free_cpufreq_table(struct device *dev,
+                                  struct cpufreq_frequency_table **table)
+{
+       if (!table)
+               return;
+
+       kfree(*table);
+       *table = NULL;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
+#endif /* CONFIG_CPU_FREQ */
+
+/* Required only for V1 bindings, as v2 can manage it from DT itself */
+int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
+{
+       struct device_list_opp *list_dev;
+       struct device_opp *dev_opp;
+       struct device *dev;
+       int cpu, ret = 0;
+
+       rcu_read_lock();
+
+       dev_opp = _find_device_opp(cpu_dev);
+       if (IS_ERR(dev_opp)) {
+               ret = -EINVAL;
+               goto out_rcu_read_unlock;
+       }
+
+       for_each_cpu(cpu, cpumask) {
+               if (cpu == cpu_dev->id)
+                       continue;
+
+               dev = get_cpu_device(cpu);
+               if (!dev) {
+                       dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
+                               __func__, cpu);
+                       continue;
+               }
+
+               list_dev = _add_list_dev(dev, dev_opp);
+               if (!list_dev) {
+                       dev_err(dev, "%s: failed to add list-dev for cpu%d device\n",
+                               __func__, cpu);
+                       continue;
+               }
+       }
+out_rcu_read_unlock:
+       rcu_read_unlock();
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
+
+#ifdef CONFIG_OF
+void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask)
+{
+       struct device *cpu_dev;
+       int cpu;
+
+       WARN_ON(cpumask_empty(cpumask));
+
+       for_each_cpu(cpu, cpumask) {
+               cpu_dev = get_cpu_device(cpu);
+               if (!cpu_dev) {
+                       pr_err("%s: failed to get cpu%d device\n", __func__,
+                              cpu);
+                       continue;
+               }
+
+               dev_pm_opp_of_remove_table(cpu_dev);
+       }
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
+
+int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask)
+{
+       struct device *cpu_dev;
+       int cpu, ret = 0;
+
+       WARN_ON(cpumask_empty(cpumask));
+
+       for_each_cpu(cpu, cpumask) {
+               cpu_dev = get_cpu_device(cpu);
+               if (!cpu_dev) {
+                       pr_err("%s: failed to get cpu%d device\n", __func__,
+                              cpu);
+                       continue;
+               }
+
+               ret = dev_pm_opp_of_add_table(cpu_dev);
+               if (ret) {
+                       pr_err("%s: couldn't find opp table for cpu:%d, %d\n",
+                              __func__, cpu, ret);
+
+                       /* Free all other OPPs */
+                       dev_pm_opp_of_cpumask_remove_table(cpumask);
+                       break;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
+
+/*
+ * Works only for OPP v2 bindings.
+ *
+ * cpumask should be already set to mask of cpu_dev->id.
+ * Returns -ENOENT if operating-points-v2 bindings aren't supported.
+ */
+int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
+{
+       struct device_node *np, *tmp_np;
+       struct device *tcpu_dev;
+       int cpu, ret = 0;
+
+       /* Get OPP descriptor node */
+       np = _of_get_opp_desc_node(cpu_dev);
+       if (!np) {
+               dev_dbg(cpu_dev, "%s: Couldn't find cpu_dev node.\n", __func__);
+               return -ENOENT;
+       }
+
+       /* OPPs are shared ? */
+       if (!of_property_read_bool(np, "opp-shared"))
+               goto put_cpu_node;
+
+       for_each_possible_cpu(cpu) {
+               if (cpu == cpu_dev->id)
+                       continue;
+
+               tcpu_dev = get_cpu_device(cpu);
+               if (!tcpu_dev) {
+                       dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
+                               __func__, cpu);
+                       ret = -ENODEV;
+                       goto put_cpu_node;
+               }
+
+               /* Get OPP descriptor node */
+               tmp_np = _of_get_opp_desc_node(tcpu_dev);
+               if (!tmp_np) {
+                       dev_err(tcpu_dev, "%s: Couldn't find tcpu_dev node.\n",
+                               __func__);
+                       ret = -ENOENT;
+                       goto put_cpu_node;
+               }
+
+               /* CPUs are sharing opp node */
+               if (np == tmp_np)
+                       cpumask_set_cpu(cpu, cpumask);
+
+               of_node_put(tmp_np);
+       }
+
+put_cpu_node:
+       of_node_put(np);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
+#endif
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
new file mode 100644 (file)
index 0000000..dcb38f7
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Generic OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *     Nishanth Menon
+ *     Romit Dasgupta
+ *     Kevin Hilman
+ *
+ * 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 __DRIVER_OPP_H__
+#define __DRIVER_OPP_H__
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/pm_opp.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+
+/*
+ * Internal data structure organization with the OPP layer library is as
+ * follows:
+ * dev_opp_list (root)
+ *     |- device 1 (represents voltage domain 1)
+ *     |       |- opp 1 (availability, freq, voltage)
+ *     |       |- opp 2 ..
+ *     ...     ...
+ *     |       `- opp n ..
+ *     |- device 2 (represents the next voltage domain)
+ *     ...
+ *     `- device m (represents mth voltage domain)
+ * device 1, 2.. are represented by dev_opp structure while each opp
+ * is represented by the opp structure.
+ */
+
+/**
+ * struct dev_pm_opp - Generic OPP description structure
+ * @node:      opp list node. The nodes are maintained throughout the lifetime
+ *             of boot. It is expected only an optimal set of OPPs are
+ *             added to the library by the SoC framework.
+ *             RCU usage: opp list is traversed with RCU locks. node
+ *             modification is possible realtime, hence the modifications
+ *             are protected by the dev_opp_list_lock for integrity.
+ *             IMPORTANT: the opp nodes should be maintained in increasing
+ *             order.
+ * @dynamic:   not-created from static DT entries.
+ * @available: true/false - marks if this OPP as available or not
+ * @turbo:     true if turbo (boost) OPP
+ * @rate:      Frequency in hertz
+ * @u_volt:    Target voltage in microvolts corresponding to this OPP
+ * @u_volt_min:        Minimum voltage in microvolts corresponding to this OPP
+ * @u_volt_max:        Maximum voltage in microvolts corresponding to this OPP
+ * @u_amp:     Maximum current drawn by the device in microamperes
+ * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
+ *             frequency from any other OPP's frequency.
+ * @dev_opp:   points back to the device_opp struct this opp belongs to
+ * @rcu_head:  RCU callback head used for deferred freeing
+ * @np:                OPP's device node.
+ *
+ * This structure stores the OPP information for a given device.
+ */
+struct dev_pm_opp {
+       struct list_head node;
+
+       bool available;
+       bool dynamic;
+       bool turbo;
+       unsigned long rate;
+
+       unsigned long u_volt;
+       unsigned long u_volt_min;
+       unsigned long u_volt_max;
+       unsigned long u_amp;
+       unsigned long clock_latency_ns;
+
+       struct device_opp *dev_opp;
+       struct rcu_head rcu_head;
+
+       struct device_node *np;
+};
+
+/**
+ * struct device_list_opp - devices managed by 'struct device_opp'
+ * @node:      list node
+ * @dev:       device to which the struct object belongs
+ * @rcu_head:  RCU callback head used for deferred freeing
+ *
+ * This is an internal data structure maintaining the list of devices that are
+ * managed by 'struct device_opp'.
+ */
+struct device_list_opp {
+       struct list_head node;
+       const struct device *dev;
+       struct rcu_head rcu_head;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:      list node - contains the devices with OPPs that
+ *             have been registered. Nodes once added are not modified in this
+ *             list.
+ *             RCU usage: nodes are not modified in the list of device_opp,
+ *             however addition is possible and is secured by dev_opp_list_lock
+ * @srcu_head: notifier head to notify the OPP availability changes.
+ * @rcu_head:  RCU callback head used for deferred freeing
+ * @dev_list:  list of devices that share these OPPs
+ * @opp_list:  list of opps
+ * @np:                struct device_node pointer for opp's DT node.
+ * @shared_opp: OPP is shared between multiple devices.
+ *
+ * This is an internal data structure maintaining the link to opps attached to
+ * a device. This structure is not meant to be shared to users as it is
+ * meant for book keeping and private to OPP library.
+ *
+ * Because the opp structures can be used from both rcu and srcu readers, we
+ * need to wait for the grace period of both of them before freeing any
+ * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
+ */
+struct device_opp {
+       struct list_head node;
+
+       struct srcu_notifier_head srcu_head;
+       struct rcu_head rcu_head;
+       struct list_head dev_list;
+       struct list_head opp_list;
+
+       struct device_node *np;
+       unsigned long clock_latency_ns_max;
+       bool shared_opp;
+       struct dev_pm_opp *suspend_opp;
+};
+
+/* Routines internal to opp core */
+struct device_opp *_find_device_opp(struct device *dev);
+struct device_list_opp *_add_list_dev(const struct device *dev,
+                                     struct device_opp *dev_opp);
+struct device_node *_of_get_opp_desc_node(struct device *dev);
+
+#endif         /* __DRIVER_OPP_H__ */
index 51f15bc15774250a203b46c44b5682b36f450f1d..a1e0b9ab847a345c6a09adab3ff9f2fd9af3ad3e 100644 (file)
@@ -25,6 +25,9 @@
  */
 bool events_check_enabled __read_mostly;
 
+/* First wakeup IRQ seen by the kernel in the last cycle. */
+unsigned int pm_wakeup_irq __read_mostly;
+
 /* If set and the system is suspending, terminate the suspend. */
 static bool pm_abort_suspend __read_mostly;
 
@@ -91,7 +94,7 @@ struct wakeup_source *wakeup_source_create(const char *name)
        if (!ws)
                return NULL;
 
-       wakeup_source_prepare(ws, name ? kstrdup(name, GFP_KERNEL) : NULL);
+       wakeup_source_prepare(ws, name ? kstrdup_const(name, GFP_KERNEL) : NULL);
        return ws;
 }
 EXPORT_SYMBOL_GPL(wakeup_source_create);
@@ -154,7 +157,7 @@ void wakeup_source_destroy(struct wakeup_source *ws)
 
        wakeup_source_drop(ws);
        wakeup_source_record(ws);
-       kfree(ws->name);
+       kfree_const(ws->name);
        kfree(ws);
 }
 EXPORT_SYMBOL_GPL(wakeup_source_destroy);
@@ -868,6 +871,15 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup);
 void pm_wakeup_clear(void)
 {
        pm_abort_suspend = false;
+       pm_wakeup_irq = 0;
+}
+
+void pm_system_irq_wakeup(unsigned int irq_number)
+{
+       if (pm_wakeup_irq == 0) {
+               pm_wakeup_irq = irq_number;
+               pm_system_wakeup();
+       }
 }
 
 /**
index 2d75366c61e03c7188e2839ec1e8d727d3365966..de40623bbd8a748fd81f3208810046d05861a75c 100644 (file)
@@ -134,7 +134,7 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
        if (is_of_node(fwnode))
                return of_property_read_bool(to_of_node(fwnode), propname);
        else if (is_acpi_node(fwnode))
-               return !acpi_dev_prop_get(to_acpi_node(fwnode), propname, NULL);
+               return !acpi_node_prop_get(fwnode, propname, NULL);
 
        return !!pset_prop_get(to_pset(fwnode), propname);
 }
@@ -287,6 +287,28 @@ int device_property_read_string(struct device *dev, const char *propname,
 }
 EXPORT_SYMBOL_GPL(device_property_read_string);
 
+/**
+ * device_property_match_string - find a string in an array and return index
+ * @dev: Device to get the property of
+ * @propname: Name of the property holding the array
+ * @string: String to look for
+ *
+ * Find a given string in a string array and if it is found return the
+ * index back.
+ *
+ * Return: %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,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int device_property_match_string(struct device *dev, const char *propname,
+                                const char *string)
+{
+       return fwnode_property_match_string(dev_fwnode(dev), propname, string);
+}
+EXPORT_SYMBOL_GPL(device_property_match_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))
@@ -298,8 +320,8 @@ EXPORT_SYMBOL_GPL(device_property_read_string);
                _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \
                                               _type_, _val_, _nval_); \
        else if (is_acpi_node(_fwnode_)) \
-               _ret_ = acpi_dev_prop_read(to_acpi_node(_fwnode_), _propname_, \
-                                          _proptype_, _val_, _nval_); \
+               _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \
+                                           _val_, _nval_); \
        else if (is_pset(_fwnode_)) \
                _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \
                                             _proptype_, _val_, _nval_); \
@@ -440,8 +462,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
                                                      propname, val, nval) :
                        of_property_count_strings(to_of_node(fwnode), propname);
        else if (is_acpi_node(fwnode))
-               return acpi_dev_prop_read(to_acpi_node(fwnode), propname,
-                                         DEV_PROP_STRING, val, nval);
+               return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
+                                          val, nval);
        else if (is_pset(fwnode))
                return pset_prop_read_array(to_pset(fwnode), propname,
                                            DEV_PROP_STRING, val, nval);
@@ -470,14 +492,60 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
        if (is_of_node(fwnode))
                return of_property_read_string(to_of_node(fwnode), propname, val);
        else if (is_acpi_node(fwnode))
-               return acpi_dev_prop_read(to_acpi_node(fwnode), propname,
-                                         DEV_PROP_STRING, val, 1);
+               return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
+                                          val, 1);
 
        return pset_prop_read_array(to_pset(fwnode), propname,
                                    DEV_PROP_STRING, val, 1);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_string);
 
+/**
+ * fwnode_property_match_string - find a string in an array and return index
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property holding the array
+ * @string: String to look for
+ *
+ * Find a given string in a string array and if it is found return the
+ * index back.
+ *
+ * Return: %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,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_match_string(struct fwnode_handle *fwnode,
+       const char *propname, const char *string)
+{
+       const char **values;
+       int nval, ret, i;
+
+       nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0);
+       if (nval < 0)
+               return nval;
+
+       values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
+       if (!values)
+               return -ENOMEM;
+
+       ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
+       if (ret < 0)
+               goto out;
+
+       ret = -ENODATA;
+       for (i = 0; i < nval; i++) {
+               if (!strcmp(values[i], string)) {
+                       ret = i;
+                       break;
+               }
+       }
+out:
+       kfree(values);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_match_string);
+
 /**
  * device_get_next_child_node - Return the next child node handle for a device
  * @dev: Device to find the next child node for.
@@ -493,11 +561,7 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
                if (node)
                        return &node->fwnode;
        } else if (IS_ENABLED(CONFIG_ACPI)) {
-               struct acpi_device *node;
-
-               node = acpi_get_next_child(dev, to_acpi_node(child));
-               if (node)
-                       return acpi_fwnode_handle(node);
+               return acpi_get_next_subnode(dev, child);
        }
        return NULL;
 }
index 8a06b8e7ca43189586a4c4e700f74e2b82c492cb..71cfdf7c97086273b1cc8ae1235ecf919abcfda1 100644 (file)
@@ -2,6 +2,14 @@ menu "Clock Source drivers"
 
 config CLKSRC_OF
        bool
+       select CLKSRC_PROBE
+
+config CLKSRC_ACPI
+       bool
+       select CLKSRC_PROBE
+
+config CLKSRC_PROBE
+       bool
 
 config CLKSRC_I8253
        bool
@@ -131,6 +139,7 @@ config CLKSRC_STM32
 config ARM_ARCH_TIMER
        bool
        select CLKSRC_OF if OF
+       select CLKSRC_ACPI if ACPI
 
 config ARM_ARCH_TIMER_EVTSTREAM
        bool "Support for ARM architected timer event stream generation"
index 063d78607c993d726639c8cd858029278c62bf5b..56bd16e77ae37147da0fa4e977adffcb9bc1a4c6 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_CLKSRC_OF)        += clksrc-of.o
+obj-$(CONFIG_CLKSRC_PROBE)     += clksrc-probe.o
 obj-$(CONFIG_ATMEL_PIT)                += timer-atmel-pit.o
 obj-$(CONFIG_ATMEL_ST)         += timer-atmel-st.o
 obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
index d6e3e49399dd40558823c8db833f2bf8e258b662..c64d543d64bf69576d9d75ffc54839439c70ea9b 100644 (file)
@@ -864,13 +864,5 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
        arch_timer_init();
        return 0;
 }
-
-/* Initialize all the generic timers presented in GTDT */
-void __init acpi_generic_timer_init(void)
-{
-       if (acpi_disabled)
-               return;
-
-       acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init);
-}
+CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
 #endif
similarity index 91%
rename from drivers/clocksource/clksrc-of.c
rename to drivers/clocksource/clksrc-probe.c
index 0093a8e49e14d67af9538d8c98c6265d5ad6bedb..7cb6c923a836f141dd5424c34039fe11a8cbe81e 100644 (file)
@@ -14,6 +14,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/clocksource.h>
@@ -23,7 +24,7 @@ extern struct of_device_id __clksrc_of_table[];
 static const struct of_device_id __clksrc_of_table_sentinel
        __used __section(__clksrc_of_table_end);
 
-void __init clocksource_of_init(void)
+void __init clocksource_probe(void)
 {
        struct device_node *np;
        const struct of_device_id *match;
@@ -38,6 +39,9 @@ void __init clocksource_of_init(void)
                init_func(np);
                clocksources++;
        }
+
+       clocksources += acpi_probe_device_table(clksrc);
+
        if (!clocksources)
                pr_crit("%s: no matching clocksources found\n", __func__);
 }
index c737f7359974b1afe98650b05c2e67c27351d184..1582c1c016b098b7d40cccbaf52f7d715a0586d2 100644 (file)
@@ -237,3 +237,20 @@ config ARM_PXA2xx_CPUFREQ
          This add the CPUFreq driver support for Intel PXA2xx SOCs.
 
          If in doubt, say N.
+
+config ACPI_CPPC_CPUFREQ
+       tristate "CPUFreq driver based on the ACPI CPPC spec"
+       depends on ACPI
+       select ACPI_CPPC_LIB
+       default n
+       help
+         This adds a CPUFreq driver which uses CPPC methods
+         as described in the ACPIv5.1 spec. CPPC stands for
+         Collaborative Processor Performance Controls. It
+         is based on an abstract continuous scale of CPU
+         performance values which allows the remote power
+         processor to flexibly optimize for power and
+         performance. CPPC relies on power management firmware
+         support for its operation.
+
+         If in doubt, say N.
index c59bdcb83217071087cc0a90ef62e5cd01ce38d7..adbd1de1cea55cbe6777d3a1c4dab546a6a68adf 100644 (file)
@@ -5,6 +5,7 @@
 config X86_INTEL_PSTATE
        bool "Intel P state control"
        depends on X86
+       select ACPI_PROCESSOR if ACPI
        help
           This driver provides a P state for Intel core processors.
          The driver implements an internal governor and will become
index ccfaa4c68a9a236998015e2fe2af3700759e6f3b..c0af1a1281c89134269445f9330d4d449c37135e 100644 (file)
@@ -1,6 +1,5 @@
 # CPUfreq core
 obj-$(CONFIG_CPU_FREQ)                 += cpufreq.o freq_table.o
-obj-$(CONFIG_PM_OPP)                   += cpufreq_opp.o
 
 # CPUfreq stats
 obj-$(CONFIG_CPU_FREQ_STAT)             += cpufreq_stats.o
@@ -77,6 +76,8 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ)               += spear-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA20_CPUFREQ)      += tegra20-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)     += tegra124-cpufreq.o
 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
+obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
+
 
 ##################################################################################
 # PowerPC platform drivers
index a211f7db9d32d20bbc6c5a471399ee778941735d..b88889d9387ed5d5d3183c6d19b7fc2c8208d230 100644 (file)
@@ -28,7 +28,7 @@ struct cpufreq_arm_bL_ops {
 
        /*
         * This must set opp table for cpu_dev in a similar way as done by
-        * of_init_opp_table().
+        * dev_pm_opp_of_add_table().
         */
        int (*init_opp_table)(struct device *cpu_dev);
 
index 36d91dba29652c7cbb33bb1a4e1d37bb1d37f628..16ddeefe94433a4edb369636131a4bd69912ccf7 100644 (file)
@@ -54,7 +54,7 @@ static int dt_init_opp_table(struct device *cpu_dev)
                return -ENOENT;
        }
 
-       ret = of_init_opp_table(cpu_dev);
+       ret = dev_pm_opp_of_add_table(cpu_dev);
        of_node_put(np);
 
        return ret;
@@ -82,7 +82,7 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = {
        .name   = "dt-bl",
        .get_transition_latency = dt_get_transition_latency,
        .init_opp_table = dt_init_opp_table,
-       .free_opp_table = of_free_opp_table,
+       .free_opp_table = dev_pm_opp_of_remove_table,
 };
 
 static int generic_bL_probe(struct platform_device *pdev)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
new file mode 100644 (file)
index 0000000..93c219f
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * CPPC (Collaborative Processor Performance Control) driver for
+ * interfacing with the CPUfreq layer and governors. See
+ * cppc_acpi.c for CPPC specific methods.
+ *
+ * (C) Copyright 2014, 2015 Linaro Ltd.
+ * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#define pr_fmt(fmt)    "CPPC Cpufreq:" fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/vmalloc.h>
+
+#include <acpi/cppc_acpi.h>
+
+/*
+ * These structs contain information parsed from per CPU
+ * ACPI _CPC structures.
+ * e.g. For each CPU the highest, lowest supported
+ * performance capabilities, desired performance level
+ * requested etc.
+ */
+static struct cpudata **all_cpu_data;
+
+static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
+               unsigned int target_freq,
+               unsigned int relation)
+{
+       struct cpudata *cpu;
+       struct cpufreq_freqs freqs;
+       int ret = 0;
+
+       cpu = all_cpu_data[policy->cpu];
+
+       cpu->perf_ctrls.desired_perf = target_freq;
+       freqs.old = policy->cur;
+       freqs.new = target_freq;
+
+       cpufreq_freq_transition_begin(policy, &freqs);
+       ret = cppc_set_perf(cpu->cpu, &cpu->perf_ctrls);
+       cpufreq_freq_transition_end(policy, &freqs, ret != 0);
+
+       if (ret)
+               pr_debug("Failed to set target on CPU:%d. ret:%d\n",
+                               cpu->cpu, ret);
+
+       return ret;
+}
+
+static int cppc_verify_policy(struct cpufreq_policy *policy)
+{
+       cpufreq_verify_within_cpu_limits(policy);
+       return 0;
+}
+
+static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
+{
+       int cpu_num = policy->cpu;
+       struct cpudata *cpu = all_cpu_data[cpu_num];
+       int ret;
+
+       cpu->perf_ctrls.desired_perf = cpu->perf_caps.lowest_perf;
+
+       ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);
+       if (ret)
+               pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
+                               cpu->perf_caps.lowest_perf, cpu_num, ret);
+}
+
+static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       struct cpudata *cpu;
+       unsigned int cpu_num = policy->cpu;
+       int ret = 0;
+
+       cpu = all_cpu_data[policy->cpu];
+
+       cpu->cpu = cpu_num;
+       ret = cppc_get_perf_caps(policy->cpu, &cpu->perf_caps);
+
+       if (ret) {
+               pr_debug("Err reading CPU%d perf capabilities. ret:%d\n",
+                               cpu_num, ret);
+               return ret;
+       }
+
+       policy->min = cpu->perf_caps.lowest_perf;
+       policy->max = cpu->perf_caps.highest_perf;
+       policy->cpuinfo.min_freq = policy->min;
+       policy->cpuinfo.max_freq = policy->max;
+
+       if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+               cpumask_copy(policy->cpus, cpu->shared_cpu_map);
+       else {
+               /* Support only SW_ANY for now. */
+               pr_debug("Unsupported CPU co-ord type\n");
+               return -EFAULT;
+       }
+
+       cpumask_set_cpu(policy->cpu, policy->cpus);
+       cpu->cur_policy = policy;
+
+       /* Set policy->cur to max now. The governors will adjust later. */
+       policy->cur = cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf;
+
+       ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);
+       if (ret)
+               pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
+                               cpu->perf_caps.highest_perf, cpu_num, ret);
+
+       return ret;
+}
+
+static struct cpufreq_driver cppc_cpufreq_driver = {
+       .flags = CPUFREQ_CONST_LOOPS,
+       .verify = cppc_verify_policy,
+       .target = cppc_cpufreq_set_target,
+       .init = cppc_cpufreq_cpu_init,
+       .stop_cpu = cppc_cpufreq_stop_cpu,
+       .name = "cppc_cpufreq",
+};
+
+static int __init cppc_cpufreq_init(void)
+{
+       int i, ret = 0;
+       struct cpudata *cpu;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       all_cpu_data = kzalloc(sizeof(void *) * num_possible_cpus(), GFP_KERNEL);
+       if (!all_cpu_data)
+               return -ENOMEM;
+
+       for_each_possible_cpu(i) {
+               all_cpu_data[i] = kzalloc(sizeof(struct cpudata), GFP_KERNEL);
+               if (!all_cpu_data[i])
+                       goto out;
+
+               cpu = all_cpu_data[i];
+               if (!zalloc_cpumask_var(&cpu->shared_cpu_map, GFP_KERNEL))
+                       goto out;
+       }
+
+       ret = acpi_get_psd_map(all_cpu_data);
+       if (ret) {
+               pr_debug("Error parsing PSD data. Aborting cpufreq registration.\n");
+               goto out;
+       }
+
+       ret = cpufreq_register_driver(&cppc_cpufreq_driver);
+       if (ret)
+               goto out;
+
+       return ret;
+
+out:
+       for_each_possible_cpu(i)
+               if (all_cpu_data[i])
+                       kfree(all_cpu_data[i]);
+
+       kfree(all_cpu_data);
+       return -ENODEV;
+}
+
+late_initcall(cppc_cpufreq_init);
index 7c0d70e2a86163b7a102276e1a51d1ceeb1b7b5c..90d64081ddb34ee8ba7a06372a269defdcf07a97 100644 (file)
@@ -216,7 +216,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
        }
 
        /* Get OPP-sharing information from "operating-points-v2" bindings */
-       ret = of_get_cpus_sharing_opps(cpu_dev, policy->cpus);
+       ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus);
        if (ret) {
                /*
                 * operating-points-v2 not supported, fallback to old method of
@@ -238,7 +238,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
         *
         * OPPs might be populated at runtime, don't check for error here
         */
-       of_cpumask_init_opp_table(policy->cpus);
+       dev_pm_opp_of_cpumask_add_table(policy->cpus);
 
        /*
         * But we need OPP table to function so if it is not there let's
@@ -261,7 +261,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
                 * OPP tables are initialized only for policy->cpu, do it for
                 * others as well.
                 */
-               ret = set_cpus_sharing_opps(cpu_dev, policy->cpus);
+               ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
                if (ret)
                        dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
                                __func__, ret);
@@ -368,7 +368,7 @@ out_free_cpufreq_table:
 out_free_priv:
        kfree(priv);
 out_free_opp:
-       of_cpumask_free_opp_table(policy->cpus);
+       dev_pm_opp_of_cpumask_remove_table(policy->cpus);
 out_node_put:
        of_node_put(np);
 out_put_reg_clk:
@@ -385,7 +385,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
 
        cpufreq_cooling_unregister(priv->cdev);
        dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
-       of_cpumask_free_opp_table(policy->related_cpus);
+       dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
        clk_put(policy->clk);
        if (!IS_ERR(priv->cpu_reg))
                regulator_put(priv->cpu_reg);
index 25c4c15103a0cd8759e006eaa10d9f9edbfb5872..7c48e7316d91e23cd8374852c477375ae65e1ccb 100644 (file)
@@ -843,18 +843,11 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
 
        down_write(&policy->rwsem);
 
-       /* Updating inactive policies is invalid, so avoid doing that. */
-       if (unlikely(policy_is_inactive(policy))) {
-               ret = -EBUSY;
-               goto unlock_policy_rwsem;
-       }
-
        if (fattr->store)
                ret = fattr->store(policy, buf, count);
        else
                ret = -EIO;
 
-unlock_policy_rwsem:
        up_write(&policy->rwsem);
 unlock:
        put_online_cpus();
@@ -880,49 +873,6 @@ static struct kobj_type ktype_cpufreq = {
        .release        = cpufreq_sysfs_release,
 };
 
-struct kobject *cpufreq_global_kobject;
-EXPORT_SYMBOL(cpufreq_global_kobject);
-
-static int cpufreq_global_kobject_usage;
-
-int cpufreq_get_global_kobject(void)
-{
-       if (!cpufreq_global_kobject_usage++)
-               return kobject_add(cpufreq_global_kobject,
-                               &cpu_subsys.dev_root->kobj, "%s", "cpufreq");
-
-       return 0;
-}
-EXPORT_SYMBOL(cpufreq_get_global_kobject);
-
-void cpufreq_put_global_kobject(void)
-{
-       if (!--cpufreq_global_kobject_usage)
-               kobject_del(cpufreq_global_kobject);
-}
-EXPORT_SYMBOL(cpufreq_put_global_kobject);
-
-int cpufreq_sysfs_create_file(const struct attribute *attr)
-{
-       int ret = cpufreq_get_global_kobject();
-
-       if (!ret) {
-               ret = sysfs_create_file(cpufreq_global_kobject, attr);
-               if (ret)
-                       cpufreq_put_global_kobject();
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(cpufreq_sysfs_create_file);
-
-void cpufreq_sysfs_remove_file(const struct attribute *attr)
-{
-       sysfs_remove_file(cpufreq_global_kobject, attr);
-       cpufreq_put_global_kobject();
-}
-EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
-
 static int add_cpu_dev_symlink(struct cpufreq_policy *policy, int cpu)
 {
        struct device *cpu_dev;
@@ -960,9 +910,6 @@ static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
 
        /* Some related CPUs might not be present (physically hotplugged) */
        for_each_cpu(j, policy->real_cpus) {
-               if (j == policy->kobj_cpu)
-                       continue;
-
                ret = add_cpu_dev_symlink(policy, j);
                if (ret)
                        break;
@@ -976,12 +923,8 @@ static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy)
        unsigned int j;
 
        /* Some related CPUs might not be present (physically hotplugged) */
-       for_each_cpu(j, policy->real_cpus) {
-               if (j == policy->kobj_cpu)
-                       continue;
-
+       for_each_cpu(j, policy->real_cpus)
                remove_cpu_dev_symlink(policy, j);
-       }
 }
 
 static int cpufreq_add_dev_interface(struct cpufreq_policy *policy)
@@ -1079,7 +1022,6 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 {
        struct device *dev = get_cpu_device(cpu);
        struct cpufreq_policy *policy;
-       int ret;
 
        if (WARN_ON(!dev))
                return NULL;
@@ -1097,13 +1039,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
        if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
                goto err_free_rcpumask;
 
-       ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &dev->kobj,
-                                  "cpufreq");
-       if (ret) {
-               pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
-               goto err_free_real_cpus;
-       }
-
+       kobject_init(&policy->kobj, &ktype_cpufreq);
        INIT_LIST_HEAD(&policy->policy_list);
        init_rwsem(&policy->rwsem);
        spin_lock_init(&policy->transition_lock);
@@ -1112,14 +1048,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
        INIT_WORK(&policy->update, handle_update);
 
        policy->cpu = cpu;
-
-       /* Set this once on allocation */
-       policy->kobj_cpu = cpu;
-
        return policy;
 
-err_free_real_cpus:
-       free_cpumask_var(policy->real_cpus);
 err_free_rcpumask:
        free_cpumask_var(policy->related_cpus);
 err_free_cpumask:
@@ -1221,9 +1151,19 @@ static int cpufreq_online(unsigned int cpu)
 
        if (new_policy) {
                /* related_cpus should at least include policy->cpus. */
-               cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+               cpumask_copy(policy->related_cpus, policy->cpus);
                /* Remember CPUs present at the policy creation time. */
                cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask);
+
+               /* Name and add the kobject */
+               ret = kobject_add(&policy->kobj, cpufreq_global_kobject,
+                                 "policy%u",
+                                 cpumask_first(policy->related_cpus));
+               if (ret) {
+                       pr_err("%s: failed to add policy->kobj: %d\n", __func__,
+                              ret);
+                       goto out_exit_policy;
+               }
        }
 
        /*
@@ -1467,22 +1407,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
                return;
        }
 
-       if (cpu != policy->kobj_cpu) {
-               remove_cpu_dev_symlink(policy, cpu);
-       } else {
-               /*
-                * The CPU owning the policy object is going away.  Move it to
-                * another suitable CPU.
-                */
-               unsigned int new_cpu = cpumask_first(policy->real_cpus);
-               struct device *new_dev = get_cpu_device(new_cpu);
-
-               dev_dbg(dev, "%s: Moving policy object to CPU%u\n", __func__, new_cpu);
-
-               sysfs_remove_link(&new_dev->kobj, "cpufreq");
-               policy->kobj_cpu = new_cpu;
-               WARN_ON(kobject_move(&policy->kobj, &new_dev->kobj));
-       }
+       remove_cpu_dev_symlink(policy, cpu);
 }
 
 static void handle_update(struct work_struct *work)
@@ -2425,7 +2350,7 @@ static int create_boost_sysfs_file(void)
        if (!cpufreq_driver->set_boost)
                cpufreq_driver->set_boost = cpufreq_boost_set_sw;
 
-       ret = cpufreq_sysfs_create_file(&boost.attr);
+       ret = sysfs_create_file(cpufreq_global_kobject, &boost.attr);
        if (ret)
                pr_err("%s: cannot register global BOOST sysfs file\n",
                       __func__);
@@ -2436,7 +2361,7 @@ static int create_boost_sysfs_file(void)
 static void remove_boost_sysfs_file(void)
 {
        if (cpufreq_boost_supported())
-               cpufreq_sysfs_remove_file(&boost.attr);
+               sysfs_remove_file(cpufreq_global_kobject, &boost.attr);
 }
 
 int cpufreq_enable_boost_support(void)
@@ -2584,12 +2509,15 @@ static struct syscore_ops cpufreq_syscore_ops = {
        .shutdown = cpufreq_suspend,
 };
 
+struct kobject *cpufreq_global_kobject;
+EXPORT_SYMBOL(cpufreq_global_kobject);
+
 static int __init cpufreq_core_init(void)
 {
        if (cpufreq_disabled())
                return -ENODEV;
 
-       cpufreq_global_kobject = kobject_create();
+       cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
        BUG_ON(!cpufreq_global_kobject);
 
        register_syscore_ops(&cpufreq_syscore_ops);
index 84a1506950a73ab7adb0d96a3cfa584200a1f4c1..1fa1deb6e91fcbb25b01f8c8e0c23438a0e2bcb4 100644 (file)
 
 static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);
 
+static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
+                                  unsigned int event);
+
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+static
+#endif
+struct cpufreq_governor cpufreq_gov_conservative = {
+       .name                   = "conservative",
+       .governor               = cs_cpufreq_governor_dbs,
+       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+       .owner                  = THIS_MODULE,
+};
+
 static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
                                           struct cpufreq_policy *policy)
 {
@@ -119,12 +132,14 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
        struct cpufreq_freqs *freq = data;
        struct cs_cpu_dbs_info_s *dbs_info =
                                        &per_cpu(cs_cpu_dbs_info, freq->cpu);
-       struct cpufreq_policy *policy;
+       struct cpufreq_policy *policy = cpufreq_cpu_get_raw(freq->cpu);
 
-       if (!dbs_info->enable)
+       if (!policy)
                return 0;
 
-       policy = dbs_info->cdbs.shared->policy;
+       /* policy isn't governed by conservative governor */
+       if (policy->governor != &cpufreq_gov_conservative)
+               return 0;
 
        /*
         * we only care if our internally tracked freq moves outside the 'valid'
@@ -367,16 +382,6 @@ static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
        return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
 }
 
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_conservative = {
-       .name                   = "conservative",
-       .governor               = cs_cpufreq_governor_dbs,
-       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
-       .owner                  = THIS_MODULE,
-};
-
 static int __init cpufreq_gov_dbs_init(void)
 {
        return cpufreq_register_governor(&cpufreq_gov_conservative);
index 939197ffa4ac0c0fa80ecbc854a24a9473b9a961..11258c4c1b175be37827c201a8d7a422a5d3eda3 100644 (file)
@@ -348,29 +348,21 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy,
        set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
                                        latency * LATENCY_MULTIPLIER));
 
-       if (!have_governor_per_policy()) {
-               if (WARN_ON(cpufreq_get_global_kobject())) {
-                       ret = -EINVAL;
-                       goto cdata_exit;
-               }
+       if (!have_governor_per_policy())
                cdata->gdbs_data = dbs_data;
-       }
 
        ret = sysfs_create_group(get_governor_parent_kobj(policy),
                                 get_sysfs_attr(dbs_data));
        if (ret)
-               goto put_kobj;
+               goto reset_gdbs_data;
 
        policy->governor_data = dbs_data;
 
        return 0;
 
-put_kobj:
-       if (!have_governor_per_policy()) {
+reset_gdbs_data:
+       if (!have_governor_per_policy())
                cdata->gdbs_data = NULL;
-               cpufreq_put_global_kobject();
-       }
-cdata_exit:
        cdata->exit(dbs_data, !policy->governor->initialized);
 free_common_dbs_info:
        free_common_dbs_info(policy, cdata);
@@ -394,10 +386,8 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy,
                sysfs_remove_group(get_governor_parent_kobj(policy),
                                   get_sysfs_attr(dbs_data));
 
-               if (!have_governor_per_policy()) {
+               if (!have_governor_per_policy())
                        cdata->gdbs_data = NULL;
-                       cpufreq_put_global_kobject();
-               }
 
                cdata->exit(dbs_data, policy->governor->initialized == 1);
                kfree(dbs_data);
@@ -463,7 +453,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy,
                        cdata->get_cpu_dbs_info_s(cpu);
 
                cs_dbs_info->down_skip = 0;
-               cs_dbs_info->enable = 1;
                cs_dbs_info->requested_freq = policy->cur;
        } else {
                struct od_ops *od_ops = cdata->gov_ops;
@@ -482,9 +471,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy,
 static int cpufreq_governor_stop(struct cpufreq_policy *policy,
                                 struct dbs_data *dbs_data)
 {
-       struct common_dbs_data *cdata = dbs_data->cdata;
-       unsigned int cpu = policy->cpu;
-       struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu);
+       struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(policy->cpu);
        struct cpu_common_dbs_info *shared = cdbs->shared;
 
        /* State should be equivalent to START */
@@ -493,13 +480,6 @@ static int cpufreq_governor_stop(struct cpufreq_policy *policy,
 
        gov_cancel_work(dbs_data, policy);
 
-       if (cdata->governor == GOV_CONSERVATIVE) {
-               struct cs_cpu_dbs_info_s *cs_dbs_info =
-                       cdata->get_cpu_dbs_info_s(cpu);
-
-               cs_dbs_info->enable = 0;
-       }
-
        shared->policy = NULL;
        mutex_destroy(&shared->timer_mutex);
        return 0;
index 50f1717966327d34d17a245b209799ef47f335d8..5621bb03e874e97415bbd1a790ba98b5737eac65 100644 (file)
@@ -170,7 +170,6 @@ struct cs_cpu_dbs_info_s {
        struct cpu_dbs_info cdbs;
        unsigned int down_skip;
        unsigned int requested_freq;
-       unsigned int enable:1;
 };
 
 /* Per policy Governors sysfs tunables */
index 1fa9088c84a8d3e621346a2d77e5a0aad41c4452..03ac6ce540424a189e2946a1dd98d2046cbc3622 100644 (file)
@@ -267,27 +267,19 @@ static void update_sampling_rate(struct dbs_data *dbs_data,
                dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
                cpufreq_cpu_put(policy);
 
-               mutex_lock(&dbs_info->cdbs.shared->timer_mutex);
-
-               if (!delayed_work_pending(&dbs_info->cdbs.dwork)) {
-                       mutex_unlock(&dbs_info->cdbs.shared->timer_mutex);
+               if (!delayed_work_pending(&dbs_info->cdbs.dwork))
                        continue;
-               }
 
                next_sampling = jiffies + usecs_to_jiffies(new_rate);
                appointed_at = dbs_info->cdbs.dwork.timer.expires;
 
                if (time_before(next_sampling, appointed_at)) {
-
-                       mutex_unlock(&dbs_info->cdbs.shared->timer_mutex);
                        cancel_delayed_work_sync(&dbs_info->cdbs.dwork);
-                       mutex_lock(&dbs_info->cdbs.shared->timer_mutex);
 
                        gov_queue_work(dbs_data, policy,
                                       usecs_to_jiffies(new_rate), true);
 
                }
-               mutex_unlock(&dbs_info->cdbs.shared->timer_mutex);
        }
 }
 
diff --git a/drivers/cpufreq/cpufreq_opp.c b/drivers/cpufreq/cpufreq_opp.c
deleted file mode 100644 (file)
index 0f5e6d5..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Generic OPP helper interface for CPUFreq drivers
- *
- * Copyright (C) 2009-2014 Texas Instruments Incorporated.
- *     Nishanth Menon
- *     Romit Dasgupta
- *     Kevin Hilman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/cpufreq.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/pm_opp.h>
-#include <linux/rcupdate.h>
-#include <linux/slab.h>
-
-/**
- * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
- * @dev:       device for which we do this operation
- * @table:     Cpufreq table returned back to caller
- *
- * Generate a cpufreq table for a provided device- this assumes that the
- * opp list is already initialized and ready for usage.
- *
- * This function allocates required memory for the cpufreq table. It is
- * expected that the caller does the required maintenance such as freeing
- * the table as required.
- *
- * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
- * if no memory available for the operation (table is not populated), returns 0
- * if successful and table is populated.
- *
- * WARNING: It is  important for the callers to ensure refreshing their copy of
- * the table if any of the mentioned functions have been invoked in the interim.
- *
- * Locking: The internal device_opp and opp structures are RCU protected.
- * Since we just use the regular accessor functions to access the internal data
- * structures, we use RCU read lock inside this function. As a result, users of
- * this function DONOT need to use explicit locks for invoking.
- */
-int dev_pm_opp_init_cpufreq_table(struct device *dev,
-                                 struct cpufreq_frequency_table **table)
-{
-       struct dev_pm_opp *opp;
-       struct cpufreq_frequency_table *freq_table = NULL;
-       int i, max_opps, ret = 0;
-       unsigned long rate;
-
-       rcu_read_lock();
-
-       max_opps = dev_pm_opp_get_opp_count(dev);
-       if (max_opps <= 0) {
-               ret = max_opps ? max_opps : -ENODATA;
-               goto out;
-       }
-
-       freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
-       if (!freq_table) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       for (i = 0, rate = 0; i < max_opps; i++, rate++) {
-               /* find next rate */
-               opp = dev_pm_opp_find_freq_ceil(dev, &rate);
-               if (IS_ERR(opp)) {
-                       ret = PTR_ERR(opp);
-                       goto out;
-               }
-               freq_table[i].driver_data = i;
-               freq_table[i].frequency = rate / 1000;
-
-               /* Is Boost/turbo opp ? */
-               if (dev_pm_opp_is_turbo(opp))
-                       freq_table[i].flags = CPUFREQ_BOOST_FREQ;
-       }
-
-       freq_table[i].driver_data = i;
-       freq_table[i].frequency = CPUFREQ_TABLE_END;
-
-       *table = &freq_table[0];
-
-out:
-       rcu_read_unlock();
-       if (ret)
-               kfree(freq_table);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
-
-/**
- * dev_pm_opp_free_cpufreq_table() - free the cpufreq table
- * @dev:       device for which we do this operation
- * @table:     table to free
- *
- * Free up the table allocated by dev_pm_opp_init_cpufreq_table
- */
-void dev_pm_opp_free_cpufreq_table(struct device *dev,
-                                  struct cpufreq_frequency_table **table)
-{
-       if (!table)
-               return;
-
-       kfree(*table);
-       *table = NULL;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
index 21a90ed7f3d8a32b08b9870ccf9bdce5e7527cd4..c0f3373706f4f04cd6ec197cb0791c2b3b7765de 100644 (file)
@@ -360,7 +360,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
                goto err_put_node;
        }
 
-       ret = of_init_opp_table(dvfs_info->dev);
+       ret = dev_pm_opp_of_add_table(dvfs_info->dev);
        if (ret) {
                dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret);
                goto err_put_node;
@@ -424,7 +424,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
 err_free_table:
        dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
 err_free_opp:
-       of_free_opp_table(dvfs_info->dev);
+       dev_pm_opp_of_remove_table(dvfs_info->dev);
 err_put_node:
        of_node_put(np);
        dev_err(&pdev->dev, "%s: failed initialization\n", __func__);
@@ -435,7 +435,7 @@ static int exynos_cpufreq_remove(struct platform_device *pdev)
 {
        cpufreq_unregister_driver(&exynos_driver);
        dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
-       of_free_opp_table(dvfs_info->dev);
+       dev_pm_opp_of_remove_table(dvfs_info->dev);
        return 0;
 }
 
index 380a90d3c57edda0d3e81eeeff60e01e64a0ba7b..ef1fa8145419cd1d2aa277f3dd20c9645e698203 100644 (file)
@@ -30,6 +30,10 @@ static struct clk *pll1_sw_clk;
 static struct clk *step_clk;
 static struct clk *pll2_pfd2_396m_clk;
 
+/* clk used by i.MX6UL */
+static struct clk *pll2_bus_clk;
+static struct clk *secondary_sel_clk;
+
 static struct device *cpu_dev;
 static bool free_opp;
 static struct cpufreq_frequency_table *freq_table;
@@ -91,16 +95,36 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
         * The setpoints are selected per PLL/PDF frequencies, so we need to
         * reprogram PLL for frequency scaling.  The procedure of reprogramming
         * PLL1 is as below.
-        *
+        * For i.MX6UL, it has a secondary clk mux, the cpu frequency change
+        * flow is slightly different from other i.MX6 OSC.
+        * The cpu frequeny change flow for i.MX6(except i.MX6UL) is as below:
         *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
         *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
         *  - Disable pll2_pfd2_396m_clk
         */
-       clk_set_parent(step_clk, pll2_pfd2_396m_clk);
-       clk_set_parent(pll1_sw_clk, step_clk);
-       if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
-               clk_set_rate(pll1_sys_clk, new_freq * 1000);
+       if (of_machine_is_compatible("fsl,imx6ul")) {
+               /*
+                * When changing pll1_sw_clk's parent to pll1_sys_clk,
+                * CPU may run at higher than 528MHz, this will lead to
+                * the system unstable if the voltage is lower than the
+                * voltage of 528MHz, so lower the CPU frequency to one
+                * half before changing CPU frequency.
+                */
+               clk_set_rate(arm_clk, (old_freq >> 1) * 1000);
                clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+               if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk))
+                       clk_set_parent(secondary_sel_clk, pll2_bus_clk);
+               else
+                       clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk);
+               clk_set_parent(step_clk, secondary_sel_clk);
+               clk_set_parent(pll1_sw_clk, step_clk);
+       } else {
+               clk_set_parent(step_clk, pll2_pfd2_396m_clk);
+               clk_set_parent(pll1_sw_clk, step_clk);
+               if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
+                       clk_set_rate(pll1_sys_clk, new_freq * 1000);
+                       clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+               }
        }
 
        /* Ensure the arm clock divider is what we expect */
@@ -186,6 +210,16 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
                goto put_clk;
        }
 
+       if (of_machine_is_compatible("fsl,imx6ul")) {
+               pll2_bus_clk = clk_get(cpu_dev, "pll2_bus");
+               secondary_sel_clk = clk_get(cpu_dev, "secondary_sel");
+               if (IS_ERR(pll2_bus_clk) || IS_ERR(secondary_sel_clk)) {
+                       dev_err(cpu_dev, "failed to get clocks specific to imx6ul\n");
+                       ret = -ENOENT;
+                       goto put_clk;
+               }
+       }
+
        arm_reg = regulator_get(cpu_dev, "arm");
        pu_reg = regulator_get_optional(cpu_dev, "pu");
        soc_reg = regulator_get(cpu_dev, "soc");
@@ -202,7 +236,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
         */
        num = dev_pm_opp_get_opp_count(cpu_dev);
        if (num < 0) {
-               ret = of_init_opp_table(cpu_dev);
+               ret = dev_pm_opp_of_add_table(cpu_dev);
                if (ret < 0) {
                        dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
                        goto put_reg;
@@ -312,7 +346,7 @@ free_freq_table:
        dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
 out_free_opp:
        if (free_opp)
-               of_free_opp_table(cpu_dev);
+               dev_pm_opp_of_remove_table(cpu_dev);
 put_reg:
        if (!IS_ERR(arm_reg))
                regulator_put(arm_reg);
@@ -331,6 +365,10 @@ put_clk:
                clk_put(step_clk);
        if (!IS_ERR(pll2_pfd2_396m_clk))
                clk_put(pll2_pfd2_396m_clk);
+       if (!IS_ERR(pll2_bus_clk))
+               clk_put(pll2_bus_clk);
+       if (!IS_ERR(secondary_sel_clk))
+               clk_put(secondary_sel_clk);
        of_node_put(np);
        return ret;
 }
@@ -340,7 +378,7 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
        cpufreq_unregister_driver(&imx6q_cpufreq_driver);
        dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
        if (free_opp)
-               of_free_opp_table(cpu_dev);
+               dev_pm_opp_of_remove_table(cpu_dev);
        regulator_put(arm_reg);
        if (!IS_ERR(pu_reg))
                regulator_put(pu_reg);
@@ -350,6 +388,8 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
        clk_put(pll1_sw_clk);
        clk_put(step_clk);
        clk_put(pll2_pfd2_396m_clk);
+       clk_put(pll2_bus_clk);
+       clk_put(secondary_sel_clk);
 
        return 0;
 }
index 2faa4216bf2a1c82877d722587a395c842edda27..79e3ff2771a6336b24552a794ffc37bf229a167f 100644 (file)
@@ -221,6 +221,8 @@ static const struct of_device_id integrator_cpufreq_match[] = {
        { },
 };
 
+MODULE_DEVICE_TABLE(of, integrator_cpufreq_match);
+
 static struct platform_driver integrator_cpufreq_driver = {
        .driver = {
                .name = "integrator-cpufreq",
index aa33b92b3e3e8866345e9893e3b0a880b8b1a17a..93a3c635ea2741fa4296c013b564ec6a7c27b827 100644 (file)
 #include <asm/cpu_device_id.h>
 #include <asm/cpufeature.h>
 
+#if IS_ENABLED(CONFIG_ACPI)
+#include <acpi/processor.h>
+#endif
+
 #define BYT_RATIOS             0x66a
 #define BYT_VIDS               0x66b
 #define BYT_TURBO_RATIOS       0x66c
@@ -43,7 +47,6 @@
 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
 #define fp_toint(X) ((X) >> FRAC_BITS)
 
-
 static inline int32_t mul_fp(int32_t x, int32_t y)
 {
        return ((int64_t)x * (int64_t)y) >> FRAC_BITS;
@@ -78,6 +81,7 @@ struct pstate_data {
        int     current_pstate;
        int     min_pstate;
        int     max_pstate;
+       int     max_pstate_physical;
        int     scaling;
        int     turbo_pstate;
 };
@@ -113,6 +117,9 @@ struct cpudata {
        u64     prev_mperf;
        u64     prev_tsc;
        struct sample sample;
+#if IS_ENABLED(CONFIG_ACPI)
+       struct acpi_processor_performance acpi_perf_data;
+#endif
 };
 
 static struct cpudata **all_cpu_data;
@@ -127,6 +134,7 @@ struct pstate_adjust_policy {
 
 struct pstate_funcs {
        int (*get_max)(void);
+       int (*get_max_physical)(void);
        int (*get_min)(void);
        int (*get_turbo)(void);
        int (*get_scaling)(void);
@@ -142,6 +150,7 @@ struct cpu_defaults {
 static struct pstate_adjust_policy pid_params;
 static struct pstate_funcs pstate_funcs;
 static int hwp_active;
+static int no_acpi_perf;
 
 struct perf_limits {
        int no_turbo;
@@ -154,9 +163,24 @@ struct perf_limits {
        int max_sysfs_pct;
        int min_policy_pct;
        int min_sysfs_pct;
+       int max_perf_ctl;
+       int min_perf_ctl;
+};
+
+static struct perf_limits performance_limits = {
+       .no_turbo = 0,
+       .turbo_disabled = 0,
+       .max_perf_pct = 100,
+       .max_perf = int_tofp(1),
+       .min_perf_pct = 100,
+       .min_perf = int_tofp(1),
+       .max_policy_pct = 100,
+       .max_sysfs_pct = 100,
+       .min_policy_pct = 0,
+       .min_sysfs_pct = 0,
 };
 
-static struct perf_limits limits = {
+static struct perf_limits powersave_limits = {
        .no_turbo = 0,
        .turbo_disabled = 0,
        .max_perf_pct = 100,
@@ -167,8 +191,163 @@ static struct perf_limits limits = {
        .max_sysfs_pct = 100,
        .min_policy_pct = 0,
        .min_sysfs_pct = 0,
+       .max_perf_ctl = 0,
+       .min_perf_ctl = 0,
 };
 
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+static struct perf_limits *limits = &performance_limits;
+#else
+static struct perf_limits *limits = &powersave_limits;
+#endif
+
+#if IS_ENABLED(CONFIG_ACPI)
+/*
+ * The max target pstate ratio is a 8 bit value in both PLATFORM_INFO MSR and
+ * in TURBO_RATIO_LIMIT MSR, which pstate driver stores in max_pstate and
+ * max_turbo_pstate fields. The PERF_CTL MSR contains 16 bit value for P state
+ * ratio, out of it only high 8 bits are used. For example 0x1700 is setting
+ * target ratio 0x17. The _PSS control value stores in a format which can be
+ * directly written to PERF_CTL MSR. But in intel_pstate driver this shift
+ * occurs during write to PERF_CTL (E.g. for cores core_set_pstate()).
+ * This function converts the _PSS control value to intel pstate driver format
+ * for comparison and assignment.
+ */
+static int convert_to_native_pstate_format(struct cpudata *cpu, int index)
+{
+       return cpu->acpi_perf_data.states[index].control >> 8;
+}
+
+static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
+{
+       struct cpudata *cpu;
+       int ret;
+       bool turbo_absent = false;
+       int max_pstate_index;
+       int min_pss_ctl, max_pss_ctl, turbo_pss_ctl;
+       int i;
+
+       cpu = all_cpu_data[policy->cpu];
+
+       pr_debug("intel_pstate: default limits 0x%x 0x%x 0x%x\n",
+                cpu->pstate.min_pstate, cpu->pstate.max_pstate,
+                cpu->pstate.turbo_pstate);
+
+       if (!cpu->acpi_perf_data.shared_cpu_map &&
+           zalloc_cpumask_var_node(&cpu->acpi_perf_data.shared_cpu_map,
+                                   GFP_KERNEL, cpu_to_node(policy->cpu))) {
+               return -ENOMEM;
+       }
+
+       ret = acpi_processor_register_performance(&cpu->acpi_perf_data,
+                                                 policy->cpu);
+       if (ret)
+               return ret;
+
+       /*
+        * Check if the control value in _PSS is for PERF_CTL MSR, which should
+        * guarantee that the states returned by it map to the states in our
+        * list directly.
+        */
+       if (cpu->acpi_perf_data.control_register.space_id !=
+                                               ACPI_ADR_SPACE_FIXED_HARDWARE)
+               return -EIO;
+
+       pr_debug("intel_pstate: CPU%u - ACPI _PSS perf data\n", policy->cpu);
+       for (i = 0; i < cpu->acpi_perf_data.state_count; i++)
+               pr_debug("     %cP%d: %u MHz, %u mW, 0x%x\n",
+                        (i == cpu->acpi_perf_data.state ? '*' : ' '), i,
+                        (u32) cpu->acpi_perf_data.states[i].core_frequency,
+                        (u32) cpu->acpi_perf_data.states[i].power,
+                        (u32) cpu->acpi_perf_data.states[i].control);
+
+       /*
+        * If there is only one entry _PSS, simply ignore _PSS and continue as
+        * usual without taking _PSS into account
+        */
+       if (cpu->acpi_perf_data.state_count < 2)
+               return 0;
+
+       turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
+       min_pss_ctl = convert_to_native_pstate_format(cpu,
+                                       cpu->acpi_perf_data.state_count - 1);
+       /* Check if there is a turbo freq in _PSS */
+       if (turbo_pss_ctl <= cpu->pstate.max_pstate &&
+           turbo_pss_ctl > cpu->pstate.min_pstate) {
+               pr_debug("intel_pstate: no turbo range exists in _PSS\n");
+               limits->no_turbo = limits->turbo_disabled = 1;
+               cpu->pstate.turbo_pstate = cpu->pstate.max_pstate;
+               turbo_absent = true;
+       }
+
+       /* Check if the max non turbo p state < Intel P state max */
+       max_pstate_index = turbo_absent ? 0 : 1;
+       max_pss_ctl = convert_to_native_pstate_format(cpu, max_pstate_index);
+       if (max_pss_ctl < cpu->pstate.max_pstate &&
+           max_pss_ctl > cpu->pstate.min_pstate)
+               cpu->pstate.max_pstate = max_pss_ctl;
+
+       /* check If min perf > Intel P State min */
+       if (min_pss_ctl > cpu->pstate.min_pstate &&
+           min_pss_ctl < cpu->pstate.max_pstate) {
+               cpu->pstate.min_pstate = min_pss_ctl;
+               policy->cpuinfo.min_freq = min_pss_ctl * cpu->pstate.scaling;
+       }
+
+       if (turbo_absent)
+               policy->cpuinfo.max_freq = cpu->pstate.max_pstate *
+                                               cpu->pstate.scaling;
+       else {
+               policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate *
+                                               cpu->pstate.scaling;
+               /*
+                * The _PSS table doesn't contain whole turbo frequency range.
+                * This just contains +1 MHZ above the max non turbo frequency,
+                * with control value corresponding to max turbo ratio. But
+                * when cpufreq set policy is called, it will call with this
+                * max frequency, which will cause a reduced performance as
+                * this driver uses real max turbo frequency as the max
+                * frequeny. So correct this frequency in _PSS table to
+                * correct max turbo frequency based on the turbo ratio.
+                * Also need to convert to MHz as _PSS freq is in MHz.
+                */
+               cpu->acpi_perf_data.states[0].core_frequency =
+                                               turbo_pss_ctl * 100;
+       }
+
+       pr_debug("intel_pstate: Updated limits using _PSS 0x%x 0x%x 0x%x\n",
+                cpu->pstate.min_pstate, cpu->pstate.max_pstate,
+                cpu->pstate.turbo_pstate);
+       pr_debug("intel_pstate: policy max_freq=%d Khz min_freq = %d KHz\n",
+                policy->cpuinfo.max_freq, policy->cpuinfo.min_freq);
+
+       return 0;
+}
+
+static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
+{
+       struct cpudata *cpu;
+
+       if (!no_acpi_perf)
+               return 0;
+
+       cpu = all_cpu_data[policy->cpu];
+       acpi_processor_unregister_performance(policy->cpu);
+       return 0;
+}
+
+#else
+static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
+{
+       return 0;
+}
+
+static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
+{
+       return 0;
+}
+#endif
+
 static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
                             int deadband, int integral) {
        pid->setpoint = setpoint;
@@ -255,7 +434,7 @@ static inline void update_turbo_state(void)
 
        cpu = all_cpu_data[0];
        rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
-       limits.turbo_disabled =
+       limits->turbo_disabled =
                (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ||
                 cpu->pstate.max_pstate == cpu->pstate.turbo_pstate);
 }
@@ -274,14 +453,14 @@ static void intel_pstate_hwp_set(void)
 
        for_each_online_cpu(cpu) {
                rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
-               adj_range = limits.min_perf_pct * range / 100;
+               adj_range = limits->min_perf_pct * range / 100;
                min = hw_min + adj_range;
                value &= ~HWP_MIN_PERF(~0L);
                value |= HWP_MIN_PERF(min);
 
-               adj_range = limits.max_perf_pct * range / 100;
+               adj_range = limits->max_perf_pct * range / 100;
                max = hw_min + adj_range;
-               if (limits.no_turbo) {
+               if (limits->no_turbo) {
                        hw_max = HWP_GUARANTEED_PERF(cap);
                        if (hw_max < max)
                                max = hw_max;
@@ -350,7 +529,7 @@ static void __init intel_pstate_debug_expose_params(void)
        static ssize_t show_##file_name                                 \
        (struct kobject *kobj, struct attribute *attr, char *buf)       \
        {                                                               \
-               return sprintf(buf, "%u\n", limits.object);             \
+               return sprintf(buf, "%u\n", limits->object);            \
        }
 
 static ssize_t show_turbo_pct(struct kobject *kobj,
@@ -386,10 +565,10 @@ static ssize_t show_no_turbo(struct kobject *kobj,
        ssize_t ret;
 
        update_turbo_state();
-       if (limits.turbo_disabled)
-               ret = sprintf(buf, "%u\n", limits.turbo_disabled);
+       if (limits->turbo_disabled)
+               ret = sprintf(buf, "%u\n", limits->turbo_disabled);
        else
-               ret = sprintf(buf, "%u\n", limits.no_turbo);
+               ret = sprintf(buf, "%u\n", limits->no_turbo);
 
        return ret;
 }
@@ -405,12 +584,12 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
                return -EINVAL;
 
        update_turbo_state();
-       if (limits.turbo_disabled) {
+       if (limits->turbo_disabled) {
                pr_warn("intel_pstate: Turbo disabled by BIOS or unavailable on processor\n");
                return -EPERM;
        }
 
-       limits.no_turbo = clamp_t(int, input, 0, 1);
+       limits->no_turbo = clamp_t(int, input, 0, 1);
 
        if (hwp_active)
                intel_pstate_hwp_set();
@@ -428,11 +607,15 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
        if (ret != 1)
                return -EINVAL;
 
-       limits.max_sysfs_pct = clamp_t(int, input, 0 , 100);
-       limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
-       limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct);
-       limits.max_perf_pct = max(limits.min_perf_pct, limits.max_perf_pct);
-       limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+       limits->max_sysfs_pct = clamp_t(int, input, 0 , 100);
+       limits->max_perf_pct = min(limits->max_policy_pct,
+                                  limits->max_sysfs_pct);
+       limits->max_perf_pct = max(limits->min_policy_pct,
+                                  limits->max_perf_pct);
+       limits->max_perf_pct = max(limits->min_perf_pct,
+                                  limits->max_perf_pct);
+       limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
+                                 int_tofp(100));
 
        if (hwp_active)
                intel_pstate_hwp_set();
@@ -449,11 +632,15 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
        if (ret != 1)
                return -EINVAL;
 
-       limits.min_sysfs_pct = clamp_t(int, input, 0 , 100);
-       limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
-       limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct);
-       limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct);
-       limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+       limits->min_sysfs_pct = clamp_t(int, input, 0 , 100);
+       limits->min_perf_pct = max(limits->min_policy_pct,
+                                  limits->min_sysfs_pct);
+       limits->min_perf_pct = min(limits->max_policy_pct,
+                                  limits->min_perf_pct);
+       limits->min_perf_pct = min(limits->max_perf_pct,
+                                  limits->min_perf_pct);
+       limits->min_perf = div_fp(int_tofp(limits->min_perf_pct),
+                                 int_tofp(100));
 
        if (hwp_active)
                intel_pstate_hwp_set();
@@ -533,7 +720,7 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate)
        u32 vid;
 
        val = (u64)pstate << 8;
-       if (limits.no_turbo && !limits.turbo_disabled)
+       if (limits->no_turbo && !limits->turbo_disabled)
                val |= (u64)1 << 32;
 
        vid_fp = cpudata->vid.min + mul_fp(
@@ -591,7 +778,7 @@ static int core_get_min_pstate(void)
        return (value >> 40) & 0xFF;
 }
 
-static int core_get_max_pstate(void)
+static int core_get_max_pstate_physical(void)
 {
        u64 value;
 
@@ -599,6 +786,46 @@ static int core_get_max_pstate(void)
        return (value >> 8) & 0xFF;
 }
 
+static int core_get_max_pstate(void)
+{
+       u64 tar;
+       u64 plat_info;
+       int max_pstate;
+       int err;
+
+       rdmsrl(MSR_PLATFORM_INFO, plat_info);
+       max_pstate = (plat_info >> 8) & 0xFF;
+
+       err = rdmsrl_safe(MSR_TURBO_ACTIVATION_RATIO, &tar);
+       if (!err) {
+               /* Do some sanity checking for safety */
+               if (plat_info & 0x600000000) {
+                       u64 tdp_ctrl;
+                       u64 tdp_ratio;
+                       int tdp_msr;
+
+                       err = rdmsrl_safe(MSR_CONFIG_TDP_CONTROL, &tdp_ctrl);
+                       if (err)
+                               goto skip_tar;
+
+                       tdp_msr = MSR_CONFIG_TDP_NOMINAL + tdp_ctrl;
+                       err = rdmsrl_safe(tdp_msr, &tdp_ratio);
+                       if (err)
+                               goto skip_tar;
+
+                       if (tdp_ratio - 1 == tar) {
+                               max_pstate = tar;
+                               pr_debug("max_pstate=TAC %x\n", max_pstate);
+                       } else {
+                               goto skip_tar;
+                       }
+               }
+       }
+
+skip_tar:
+       return max_pstate;
+}
+
 static int core_get_turbo_pstate(void)
 {
        u64 value;
@@ -622,7 +849,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
        u64 val;
 
        val = (u64)pstate << 8;
-       if (limits.no_turbo && !limits.turbo_disabled)
+       if (limits->no_turbo && !limits->turbo_disabled)
                val |= (u64)1 << 32;
 
        wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
@@ -652,6 +879,7 @@ static struct cpu_defaults core_params = {
        },
        .funcs = {
                .get_max = core_get_max_pstate,
+               .get_max_physical = core_get_max_pstate_physical,
                .get_min = core_get_min_pstate,
                .get_turbo = core_get_turbo_pstate,
                .get_scaling = core_get_scaling,
@@ -670,6 +898,7 @@ static struct cpu_defaults byt_params = {
        },
        .funcs = {
                .get_max = byt_get_max_pstate,
+               .get_max_physical = byt_get_max_pstate,
                .get_min = byt_get_min_pstate,
                .get_turbo = byt_get_turbo_pstate,
                .set = byt_set_pstate,
@@ -689,6 +918,7 @@ static struct cpu_defaults knl_params = {
        },
        .funcs = {
                .get_max = core_get_max_pstate,
+               .get_max_physical = core_get_max_pstate_physical,
                .get_min = core_get_min_pstate,
                .get_turbo = knl_get_turbo_pstate,
                .get_scaling = core_get_scaling,
@@ -702,7 +932,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
        int max_perf_adj;
        int min_perf;
 
-       if (limits.no_turbo || limits.turbo_disabled)
+       if (limits->no_turbo || limits->turbo_disabled)
                max_perf = cpu->pstate.max_pstate;
 
        /*
@@ -710,12 +940,23 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
         * policy, or by cpu specific default values determined through
         * experimentation.
         */
-       max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf));
-       *max = clamp_t(int, max_perf_adj,
-                       cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
+       if (limits->max_perf_ctl && limits->max_sysfs_pct >=
+                                               limits->max_policy_pct) {
+               *max = limits->max_perf_ctl;
+       } else {
+               max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf),
+                                       limits->max_perf));
+               *max = clamp_t(int, max_perf_adj, cpu->pstate.min_pstate,
+                              cpu->pstate.turbo_pstate);
+       }
 
-       min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf));
-       *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
+       if (limits->min_perf_ctl) {
+               *min = limits->min_perf_ctl;
+       } else {
+               min_perf = fp_toint(mul_fp(int_tofp(max_perf),
+                                   limits->min_perf));
+               *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
+       }
 }
 
 static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force)
@@ -743,6 +984,7 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 {
        cpu->pstate.min_pstate = pstate_funcs.get_min();
        cpu->pstate.max_pstate = pstate_funcs.get_max();
+       cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical();
        cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
        cpu->pstate.scaling = pstate_funcs.get_scaling();
 
@@ -761,7 +1003,8 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
 
        sample->freq = fp_toint(
                mul_fp(int_tofp(
-                       cpu->pstate.max_pstate * cpu->pstate.scaling / 100),
+                       cpu->pstate.max_pstate_physical *
+                       cpu->pstate.scaling / 100),
                        core_pct));
 
        sample->core_pct_busy = (int32_t)core_pct;
@@ -834,7 +1077,7 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
         * specified pstate.
         */
        core_busy = cpu->sample.core_pct_busy;
-       max_pstate = int_tofp(cpu->pstate.max_pstate);
+       max_pstate = int_tofp(cpu->pstate.max_pstate_physical);
        current_pstate = int_tofp(cpu->pstate.current_pstate);
        core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
 
@@ -988,37 +1231,63 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
 
 static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 {
+#if IS_ENABLED(CONFIG_ACPI)
+       struct cpudata *cpu;
+       int i;
+#endif
+       pr_debug("intel_pstate: %s max %u policy->max %u\n", __func__,
+                policy->cpuinfo.max_freq, policy->max);
        if (!policy->cpuinfo.max_freq)
                return -ENODEV;
 
        if (policy->policy == CPUFREQ_POLICY_PERFORMANCE &&
            policy->max >= policy->cpuinfo.max_freq) {
-               limits.min_policy_pct = 100;
-               limits.min_perf_pct = 100;
-               limits.min_perf = int_tofp(1);
-               limits.max_policy_pct = 100;
-               limits.max_perf_pct = 100;
-               limits.max_perf = int_tofp(1);
-               limits.no_turbo = 0;
+               pr_debug("intel_pstate: set performance\n");
+               limits = &performance_limits;
                return 0;
        }
 
-       limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
-       limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100);
-       limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
-       limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100);
+       pr_debug("intel_pstate: set powersave\n");
+       limits = &powersave_limits;
+       limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
+       limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100);
+       limits->max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
+       limits->max_policy_pct = clamp_t(int, limits->max_policy_pct, 0 , 100);
 
        /* Normalize user input to [min_policy_pct, max_policy_pct] */
-       limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
-       limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct);
-       limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
-       limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct);
+       limits->min_perf_pct = max(limits->min_policy_pct,
+                                  limits->min_sysfs_pct);
+       limits->min_perf_pct = min(limits->max_policy_pct,
+                                  limits->min_perf_pct);
+       limits->max_perf_pct = min(limits->max_policy_pct,
+                                  limits->max_sysfs_pct);
+       limits->max_perf_pct = max(limits->min_policy_pct,
+                                  limits->max_perf_pct);
 
        /* Make sure min_perf_pct <= max_perf_pct */
-       limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct);
+       limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct);
 
-       limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
-       limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+       limits->min_perf = div_fp(int_tofp(limits->min_perf_pct),
+                                 int_tofp(100));
+       limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
+                                 int_tofp(100));
+
+#if IS_ENABLED(CONFIG_ACPI)
+       cpu = all_cpu_data[policy->cpu];
+       for (i = 0; i < cpu->acpi_perf_data.state_count; i++) {
+               int control;
+
+               control = convert_to_native_pstate_format(cpu, i);
+               if (control * cpu->pstate.scaling == policy->max)
+                       limits->max_perf_ctl = control;
+               if (control * cpu->pstate.scaling == policy->min)
+                       limits->min_perf_ctl = control;
+       }
+
+       pr_debug("intel_pstate: max %u policy_max %u perf_ctl [0x%x-0x%x]\n",
+                policy->cpuinfo.max_freq, policy->max, limits->min_perf_ctl,
+                limits->max_perf_ctl);
+#endif
 
        if (hwp_active)
                intel_pstate_hwp_set();
@@ -1062,7 +1331,7 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
 
        cpu = all_cpu_data[policy->cpu];
 
-       if (limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
+       if (limits->min_perf_pct == 100 && limits->max_perf_pct == 100)
                policy->policy = CPUFREQ_POLICY_PERFORMANCE;
        else
                policy->policy = CPUFREQ_POLICY_POWERSAVE;
@@ -1074,18 +1343,30 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
        policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
        policy->cpuinfo.max_freq =
                cpu->pstate.turbo_pstate * cpu->pstate.scaling;
+       if (!no_acpi_perf)
+               intel_pstate_init_perf_limits(policy);
+       /*
+        * If there is no acpi perf data or error, we ignore and use Intel P
+        * state calculated limits, So this is not fatal error.
+        */
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        cpumask_set_cpu(policy->cpu, policy->cpus);
 
        return 0;
 }
 
+static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
+{
+       return intel_pstate_exit_perf_limits(policy);
+}
+
 static struct cpufreq_driver intel_pstate_driver = {
        .flags          = CPUFREQ_CONST_LOOPS,
        .verify         = intel_pstate_verify_policy,
        .setpolicy      = intel_pstate_set_policy,
        .get            = intel_pstate_get,
        .init           = intel_pstate_cpu_init,
+       .exit           = intel_pstate_cpu_exit,
        .stop_cpu       = intel_pstate_stop_cpu,
        .name           = "intel_pstate",
 };
@@ -1118,6 +1399,7 @@ static void copy_pid_params(struct pstate_adjust_policy *policy)
 static void copy_cpu_funcs(struct pstate_funcs *funcs)
 {
        pstate_funcs.get_max   = funcs->get_max;
+       pstate_funcs.get_max_physical = funcs->get_max_physical;
        pstate_funcs.get_min   = funcs->get_min;
        pstate_funcs.get_turbo = funcs->get_turbo;
        pstate_funcs.get_scaling = funcs->get_scaling;
@@ -1126,7 +1408,6 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
 }
 
 #if IS_ENABLED(CONFIG_ACPI)
-#include <acpi/processor.h>
 
 static bool intel_pstate_no_acpi_pss(void)
 {
@@ -1318,6 +1599,9 @@ static int __init intel_pstate_setup(char *str)
                force_load = 1;
        if (!strcmp(str, "hwp_only"))
                hwp_only = 1;
+       if (!strcmp(str, "no_acpi"))
+               no_acpi_perf = 1;
+
        return 0;
 }
 early_param("intel_pstate", intel_pstate_setup);
index 49caed293a3b8558c0b3057044d9e36cdea28918..83001dc5b6468529cd996e5d5a5179cd3fdc1f44 100644 (file)
@@ -344,7 +344,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
        /* Both presence and absence of sram regulator are valid cases. */
        sram_reg = regulator_get_exclusive(cpu_dev, "sram");
 
-       ret = of_init_opp_table(cpu_dev);
+       ret = dev_pm_opp_of_add_table(cpu_dev);
        if (ret) {
                pr_warn("no OPP table for cpu%d\n", cpu);
                goto out_free_resources;
@@ -378,7 +378,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
        return 0;
 
 out_free_opp_table:
-       of_free_opp_table(cpu_dev);
+       dev_pm_opp_of_remove_table(cpu_dev);
 
 out_free_resources:
        if (!IS_ERR(proc_reg))
@@ -404,7 +404,7 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
        if (!IS_ERR(info->inter_clk))
                clk_put(info->inter_clk);
 
-       of_free_opp_table(info->cpu_dev);
+       dev_pm_opp_of_remove_table(info->cpu_dev);
 }
 
 static int mtk_cpufreq_init(struct cpufreq_policy *policy)
index 64994e10638e4595c98248a5671a4201523c77be..cb501386eb6ef6beee5f91b6cd54840d31b38611 100644 (file)
@@ -327,8 +327,14 @@ static void powernv_cpufreq_throttle_check(void *data)
                if (chips[i].throttled)
                        goto next;
                chips[i].throttled = true;
-               pr_info("CPU %d on Chip %u has Pmax reduced to %d\n", cpu,
-                       chips[i].id, pmsr_pmax);
+               if (pmsr_pmax < powernv_pstate_info.nominal)
+                       pr_crit("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
+                               cpu, chips[i].id, pmsr_pmax,
+                               powernv_pstate_info.nominal);
+               else
+                       pr_info("CPU %d on Chip %u has Pmax reduced below turbo frequency (%d < %d)\n",
+                               cpu, chips[i].id, pmsr_pmax,
+                               powernv_pstate_info.max);
        } else if (chips[i].throttled) {
                chips[i].throttled = false;
                pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu,
index 8084c7f7e206320eccb6a3bb4e52b3e8e41831fb..2bd62845e9d5582e1f4bafec365794af4c975808 100644 (file)
@@ -175,9 +175,7 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
        .exit                   = tegra_cpu_exit,
        .name                   = "tegra",
        .attr                   = cpufreq_generic_attr,
-#ifdef CONFIG_PM
        .suspend                = cpufreq_generic_suspend,
-#endif
 };
 
 static int __init tegra_cpufreq_init(void)
index 980151f34707b2560aab8b1dbe84457b07308949..01a856971f05b8af0b470508dbade67981292392 100644 (file)
@@ -99,44 +99,40 @@ static struct cpuidle_driver armada38x_idle_driver = {
 
 static int mvebu_v7_cpuidle_probe(struct platform_device *pdev)
 {
-       mvebu_v7_cpu_suspend = pdev->dev.platform_data;
+       const struct platform_device_id *id = pdev->id_entry;
 
-       if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-xp"))
-               return cpuidle_register(&armadaxp_idle_driver, NULL);
-       else if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-370"))
-               return cpuidle_register(&armada370_idle_driver, NULL);
-       else if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-38x"))
-               return cpuidle_register(&armada38x_idle_driver, NULL);
-       else
+       if (!id)
                return -EINVAL;
-}
 
-static struct platform_driver armadaxp_cpuidle_plat_driver = {
-       .driver = {
-               .name = "cpuidle-armada-xp",
-       },
-       .probe = mvebu_v7_cpuidle_probe,
-};
+       mvebu_v7_cpu_suspend = pdev->dev.platform_data;
 
-module_platform_driver(armadaxp_cpuidle_plat_driver);
+       return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL);
+}
 
-static struct platform_driver armada370_cpuidle_plat_driver = {
-       .driver = {
+static const struct platform_device_id mvebu_cpuidle_ids[] = {
+       {
+               .name = "cpuidle-armada-xp",
+               .driver_data = (unsigned long)&armadaxp_idle_driver,
+       }, {
                .name = "cpuidle-armada-370",
+               .driver_data = (unsigned long)&armada370_idle_driver,
+       }, {
+               .name = "cpuidle-armada-38x",
+               .driver_data = (unsigned long)&armada38x_idle_driver,
        },
-       .probe = mvebu_v7_cpuidle_probe,
+       {}
 };
 
-module_platform_driver(armada370_cpuidle_plat_driver);
-
-static struct platform_driver armada38x_cpuidle_plat_driver = {
+static struct platform_driver mvebu_cpuidle_driver = {
+       .probe = mvebu_v7_cpuidle_probe,
        .driver = {
-               .name = "cpuidle-armada-38x",
+               .name = "cpuidle-mbevu",
+               .suppress_bind_attrs = true,
        },
-       .probe = mvebu_v7_cpuidle_probe,
+       .id_table = mvebu_cpuidle_ids,
 };
 
-module_platform_driver(armada38x_cpuidle_plat_driver);
+builtin_platform_driver(mvebu_cpuidle_driver);
 
 MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
 MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver");
index 5a635646e05cfe87a9f92083c5864827c669ccee..981a38fc4cb879b81208edd9ffa588253de53253 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/acpi.h>
 #include <linux/acpi_dma.h>
+#include <linux/property.h>
 
 static LIST_HEAD(acpi_dma_list);
 static DEFINE_MUTEX(acpi_dma_lock);
@@ -413,21 +414,29 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
  * translate the names "tx" and "rx" here based on the most common case where
  * the first FixedDMA descriptor is TX and second is RX.
  *
+ * If the device has "dma-names" property the FixedDMA descriptor indices
+ * are retrieved based on those. Otherwise the function falls back using
+ * hardcoded indices.
+ *
  * Return:
  * Pointer to appropriate dma channel on success or an error pointer.
  */
 struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
                const char *name)
 {
-       size_t index;
-
-       if (!strcmp(name, "tx"))
-               index = 0;
-       else if (!strcmp(name, "rx"))
-               index = 1;
-       else
-               return ERR_PTR(-ENODEV);
+       int index;
+
+       index = device_property_match_string(dev, "dma-names", name);
+       if (index < 0) {
+               if (!strcmp(name, "tx"))
+                       index = 0;
+               else if (!strcmp(name, "rx"))
+                       index = 1;
+               else
+                       return ERR_PTR(-ENODEV);
+       }
 
+       dev_dbg(dev, "found DMA channel \"%s\" at index %d\n", name, index);
        return acpi_dma_request_slave_chan_by_index(dev, index);
 }
 EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
index bbcac3af2a7ab84804fa862fe6a31869ca35aca3..16a7b68167444bba93e24d3d59769f0a08d55440 100644 (file)
@@ -388,6 +388,8 @@ struct acpi_gpio_lookup {
        struct acpi_gpio_info info;
        int index;
        int pin_index;
+       bool active_low;
+       struct acpi_device *adev;
        struct gpio_desc *desc;
        int n;
 };
@@ -424,6 +426,65 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
        return 1;
 }
 
+static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,
+                                    struct acpi_gpio_info *info)
+{
+       struct list_head res_list;
+       int ret;
+
+       INIT_LIST_HEAD(&res_list);
+
+       ret = acpi_dev_get_resources(lookup->adev, &res_list, acpi_find_gpio,
+                                    lookup);
+       if (ret < 0)
+               return ret;
+
+       acpi_dev_free_resource_list(&res_list);
+
+       if (!lookup->desc)
+               return -ENOENT;
+
+       if (info) {
+               *info = lookup->info;
+               if (lookup->active_low)
+                       info->active_low = lookup->active_low;
+       }
+       return 0;
+}
+
+static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
+                                    const char *propname, int index,
+                                    struct acpi_gpio_lookup *lookup)
+{
+       struct acpi_reference_args args;
+       int ret;
+
+       memset(&args, 0, sizeof(args));
+       ret = acpi_node_get_property_reference(fwnode, propname, index, &args);
+       if (ret) {
+               struct acpi_device *adev = to_acpi_device_node(fwnode);
+
+               if (!adev)
+                       return ret;
+
+               if (!acpi_get_driver_gpio_data(adev, propname, index, &args))
+                       return ret;
+       }
+       /*
+        * The property was found and resolved, so need to lookup the GPIO based
+        * on returned args.
+        */
+       lookup->adev = args.adev;
+       if (args.nargs >= 2) {
+               lookup->index = args.args[0];
+               lookup->pin_index = args.args[1];
+               /* 3rd argument, if present is used to specify active_low. */
+               if (args.nargs >= 3)
+                       lookup->active_low = !!args.args[2];
+       }
+       return 0;
+}
+
 /**
  * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
  * @adev: pointer to a ACPI device to get GPIO from
@@ -451,8 +512,6 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
                                          struct acpi_gpio_info *info)
 {
        struct acpi_gpio_lookup lookup;
-       struct list_head resource_list;
-       bool active_low = false;
        int ret;
 
        if (!adev)
@@ -462,58 +521,64 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
        lookup.index = index;
 
        if (propname) {
-               struct acpi_reference_args args;
-
                dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
 
-               memset(&args, 0, sizeof(args));
-               ret = acpi_dev_get_property_reference(adev, propname,
-                                                     index, &args);
-               if (ret) {
-                       bool found = acpi_get_driver_gpio_data(adev, propname,
-                                                              index, &args);
-                       if (!found)
-                               return ERR_PTR(ret);
-               }
+               ret = acpi_gpio_property_lookup(acpi_fwnode_handle(adev),
+                                               propname, index, &lookup);
+               if (ret)
+                       return ERR_PTR(ret);
 
-               /*
-                * The property was found and resolved so need to
-                * lookup the GPIO based on returned args instead.
-                */
-               adev = args.adev;
-               if (args.nargs >= 2) {
-                       lookup.index = args.args[0];
-                       lookup.pin_index = args.args[1];
-                       /*
-                        * 3rd argument, if present is used to
-                        * specify active_low.
-                        */
-                       if (args.nargs >= 3)
-                               active_low = !!args.args[2];
-               }
-
-               dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
-                       dev_name(&adev->dev), args.nargs,
-                       args.args[0], args.args[1], args.args[2]);
+               dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n",
+                       dev_name(&lookup.adev->dev), lookup.index,
+                       lookup.pin_index, lookup.active_low);
        } else {
                dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+               lookup.adev = adev;
        }
 
-       INIT_LIST_HEAD(&resource_list);
-       ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
-                                    &lookup);
-       if (ret < 0)
-               return ERR_PTR(ret);
+       ret = acpi_gpio_resource_lookup(&lookup, info);
+       return ret ? ERR_PTR(ret) : lookup.desc;
+}
+
+/**
+ * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources
+ * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
+ * @propname: Property name of the GPIO
+ * @index: index of GpioIo/GpioInt resource (starting from %0)
+ * @info: info pointer to fill in (optional)
+ *
+ * If @fwnode is an ACPI device object, call %acpi_get_gpiod_by_index() for it.
+ * Otherwise (ie. it is a data-only non-device object), use the property-based
+ * GPIO lookup to get to the GPIO resource with the relevant information and use
+ * that to obtain the GPIO descriptor to return.
+ */
+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
+                                     const char *propname, int index,
+                                     struct acpi_gpio_info *info)
+{
+       struct acpi_gpio_lookup lookup;
+       struct acpi_device *adev;
+       int ret;
 
-       acpi_dev_free_resource_list(&resource_list);
+       adev = to_acpi_device_node(fwnode);
+       if (adev)
+               return acpi_get_gpiod_by_index(adev, propname, index, info);
 
-       if (lookup.desc && info) {
-               *info = lookup.info;
-               if (active_low)
-                       info->active_low = active_low;
-       }
+       if (!is_acpi_data_node(fwnode))
+               return ERR_PTR(-ENODEV);
+
+       if (!propname)
+               return ERR_PTR(-EINVAL);
+
+       memset(&lookup, 0, sizeof(lookup));
+       lookup.index = index;
+
+       ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
+       if (ret)
+               return ERR_PTR(ret);
 
-       return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
+       ret = acpi_gpio_resource_lookup(&lookup, info);
+       return ret ? ERR_PTR(ret) : lookup.desc;
 }
 
 /**
index 6798355c61c6f763c6d30cc5ec623d0afd873827..a18f00fc1bb87544cc59182e6f4a5515464a2f29 100644 (file)
@@ -2209,8 +2209,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
        } else if (is_acpi_node(fwnode)) {
                struct acpi_gpio_info info;
 
-               desc = acpi_get_gpiod_by_index(to_acpi_node(fwnode), propname, 0,
-                                              &info);
+               desc = acpi_node_get_gpiod(fwnode, propname, 0, &info);
                if (!IS_ERR(desc))
                        active_low = info.active_low;
        }
index 78e634d1c719b10846e4399de1c766f644d2f31c..98ab08c0aa2d2d13344b6af003e6696129193907 100644 (file)
@@ -42,6 +42,9 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
 struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
                                          const char *propname, int index,
                                          struct acpi_gpio_info *info);
+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
+                                     const char *propname, int index,
+                                     struct acpi_gpio_info *info);
 
 int acpi_gpio_count(struct device *dev, const char *con_id);
 #else
@@ -60,7 +63,12 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
 {
        return ERR_PTR(-ENOSYS);
 }
-
+static inline struct gpio_desc *
+acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
+                   int index, struct acpi_gpio_info *info)
+{
+       return ERR_PTR(-ENXIO);
+}
 static inline int acpi_gpio_count(struct device *dev, const char *con_id)
 {
        return -ENODEV;
index db91de539ee30bfc14612f0056f3979b884ff4aa..454195709a824b3e5a346b3aa9e087672dccdcae 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/i8042.h>
 #include <linux/slab.h>
+#include <linux/suspend.h>
 
 #include <asm/io.h>
 
@@ -1170,7 +1171,8 @@ static int i8042_pm_suspend(struct device *dev)
 {
        int i;
 
-       i8042_controller_reset(true);
+       if (pm_suspend_via_firmware())
+               i8042_controller_reset(true);
 
        /* Set up serio interrupts for system wakeup. */
        for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1183,8 +1185,17 @@ static int i8042_pm_suspend(struct device *dev)
        return 0;
 }
 
+static int i8042_pm_resume_noirq(struct device *dev)
+{
+       if (!pm_resume_via_firmware())
+               i8042_interrupt(0, NULL);
+
+       return 0;
+}
+
 static int i8042_pm_resume(struct device *dev)
 {
+       bool force_reset;
        int i;
 
        for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1195,11 +1206,21 @@ static int i8042_pm_resume(struct device *dev)
        }
 
        /*
-        * On resume from S2R we always try to reset the controller
-        * to bring it in a sane state. (In case of S2D we expect
-        * BIOS to reset the controller for us.)
+        * If platform firmware was not going to be involved in suspend, we did
+        * not restore the controller state to whatever it had been at boot
+        * time, so we do not need to do anything.
         */
-       return i8042_controller_resume(true);
+       if (!pm_suspend_via_firmware())
+               return 0;
+
+       /*
+        * We only need to reset the controller if we are resuming after handing
+        * off control to the platform firmware, otherwise we can simply restore
+        * the mode.
+        */
+       force_reset = pm_resume_via_firmware();
+
+       return i8042_controller_resume(force_reset);
 }
 
 static int i8042_pm_thaw(struct device *dev)
@@ -1223,6 +1244,7 @@ static int i8042_pm_restore(struct device *dev)
 
 static const struct dev_pm_ops i8042_pm_ops = {
        .suspend        = i8042_pm_suspend,
+       .resume_noirq   = i8042_pm_resume_noirq,
        .resume         = i8042_pm_resume,
        .thaw           = i8042_pm_thaw,
        .poweroff       = i8042_pm_reset,
index 1d0e76855106cf946627dcc5c5aaa728a38c6bc8..515c823c1c95cee63b46c18bed35bb70260ae9a9 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/irqchip.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
-#include <linux/irqchip/arm-gic-acpi.h>
 
 #include <asm/cputype.h>
 #include <asm/irq.h>
@@ -1219,7 +1218,7 @@ IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init);
 #endif
 
 #ifdef CONFIG_ACPI
-static phys_addr_t dist_phy_base, cpu_phy_base __initdata;
+static phys_addr_t cpu_phy_base __initdata;
 
 static int __init
 gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
@@ -1247,61 +1246,57 @@ gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
        return 0;
 }
 
-static int __init
-gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
-                               const unsigned long end)
+/* The things you have to do to just *count* something... */
+static int __init acpi_dummy_func(struct acpi_subtable_header *header,
+                                 const unsigned long end)
 {
-       struct acpi_madt_generic_distributor *dist;
+       return 0;
+}
 
-       dist = (struct acpi_madt_generic_distributor *)header;
+static bool __init acpi_gic_redist_is_present(void)
+{
+       return acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+                                    acpi_dummy_func, 0) > 0;
+}
 
-       if (BAD_MADT_ENTRY(dist, end))
-               return -EINVAL;
+static bool __init gic_validate_dist(struct acpi_subtable_header *header,
+                                    struct acpi_probe_entry *ape)
+{
+       struct acpi_madt_generic_distributor *dist;
+       dist = (struct acpi_madt_generic_distributor *)header;
 
-       dist_phy_base = dist->base_address;
-       return 0;
+       return (dist->version == ape->driver_data &&
+               (dist->version != ACPI_MADT_GIC_VERSION_NONE ||
+                !acpi_gic_redist_is_present()));
 }
 
-int __init
-gic_v2_acpi_init(struct acpi_table_header *table)
+#define ACPI_GICV2_DIST_MEM_SIZE       (SZ_4K)
+#define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
+
+static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
+                                  const unsigned long end)
 {
+       struct acpi_madt_generic_distributor *dist;
        void __iomem *cpu_base, *dist_base;
        struct fwnode_handle *domain_handle;
        int count;
 
        /* Collect CPU base addresses */
-       count = acpi_parse_entries(ACPI_SIG_MADT,
-                                  sizeof(struct acpi_table_madt),
-                                  gic_acpi_parse_madt_cpu, table,
-                                  ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+                                     gic_acpi_parse_madt_cpu, 0);
        if (count <= 0) {
                pr_err("No valid GICC entries exist\n");
                return -EINVAL;
        }
 
-       /*
-        * Find distributor base address. We expect one distributor entry since
-        * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade.
-        */
-       count = acpi_parse_entries(ACPI_SIG_MADT,
-                                  sizeof(struct acpi_table_madt),
-                                  gic_acpi_parse_madt_distributor, table,
-                                  ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
-       if (count <= 0) {
-               pr_err("No valid GICD entries exist\n");
-               return -EINVAL;
-       } else if (count > 1) {
-               pr_err("More than one GICD entry detected\n");
-               return -EINVAL;
-       }
-
        cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
        if (!cpu_base) {
                pr_err("Unable to map GICC registers\n");
                return -ENOMEM;
        }
 
-       dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE);
+       dist = (struct acpi_madt_generic_distributor *)header;
+       dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE);
        if (!dist_base) {
                pr_err("Unable to map GICD registers\n");
                iounmap(cpu_base);
@@ -1332,4 +1327,10 @@ gic_v2_acpi_init(struct acpi_table_header *table)
        acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
        return 0;
 }
+IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+                    gic_validate_dist, ACPI_MADT_GIC_VERSION_V2,
+                    gic_v2_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v2_maybe, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+                    gic_validate_dist, ACPI_MADT_GIC_VERSION_NONE,
+                    gic_v2_acpi_init);
 #endif
index afd1af3dfe5a231692cd0904c5b5a18e5c3f8245..2b35e68bea825c3a5d132d42a2a52b2740ec1353 100644 (file)
@@ -8,7 +8,7 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/acpi_irq.h>
+#include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/of_irq.h>
 #include <linux/irqchip.h>
@@ -27,6 +27,5 @@ extern struct of_device_id __irqchip_of_table[];
 void __init irqchip_init(void)
 {
        of_irq_init(__irqchip_of_table);
-
-       acpi_irq_init();
+       acpi_probe_device_table(irqchip);
 }
index 61122fa0879b0314f9802e49b337907e0a294d86..4446fcb5effd347d87fb6314473297acc4558769 100644 (file)
@@ -682,10 +682,16 @@ static int pci_pm_prepare(struct device *dev)
        return pci_dev_keep_suspended(to_pci_dev(dev));
 }
 
+static void pci_pm_complete(struct device *dev)
+{
+       pci_dev_complete_resume(to_pci_dev(dev));
+       pm_complete_with_resume_check(dev);
+}
 
 #else /* !CONFIG_PM_SLEEP */
 
 #define pci_pm_prepare NULL
+#define pci_pm_complete        NULL
 
 #endif /* !CONFIG_PM_SLEEP */
 
@@ -1216,6 +1222,7 @@ static int pci_pm_runtime_idle(struct device *dev)
 
 static const struct dev_pm_ops pci_dev_pm_ops = {
        .prepare = pci_pm_prepare,
+       .complete = pci_pm_complete,
        .suspend = pci_pm_suspend,
        .resume = pci_pm_resume,
        .freeze = pci_pm_freeze,
index 2b28a4e77ea40308c1d10310a6947798b96db998..314db8c1047a30228f68072f820d7f40babc2ad0 100644 (file)
@@ -1741,15 +1741,7 @@ static void pci_pme_list_scan(struct work_struct *work)
        mutex_unlock(&pci_pme_list_mutex);
 }
 
-/**
- * pci_pme_active - enable or disable PCI device's PME# function
- * @dev: PCI device to handle.
- * @enable: 'true' to enable PME# generation; 'false' to disable it.
- *
- * The caller must verify that the device is capable of generating PME# before
- * calling this function with @enable equal to 'true'.
- */
-void pci_pme_active(struct pci_dev *dev, bool enable)
+static void __pci_pme_active(struct pci_dev *dev, bool enable)
 {
        u16 pmcsr;
 
@@ -1763,6 +1755,19 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
                pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
 
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
+}
+
+/**
+ * pci_pme_active - enable or disable PCI device's PME# function
+ * @dev: PCI device to handle.
+ * @enable: 'true' to enable PME# generation; 'false' to disable it.
+ *
+ * The caller must verify that the device is capable of generating PME# before
+ * calling this function with @enable equal to 'true'.
+ */
+void pci_pme_active(struct pci_dev *dev, bool enable)
+{
+       __pci_pme_active(dev, enable);
 
        /*
         * PCI (as opposed to PCIe) PME requires that the device have
@@ -2063,17 +2068,60 @@ EXPORT_SYMBOL_GPL(pci_dev_run_wake);
  * reconfigured due to wakeup settings difference between system and runtime
  * suspend and the current power state of it is suitable for the upcoming
  * (system) transition.
+ *
+ * If the device is not configured for system wakeup, disable PME for it before
+ * returning 'true' to prevent it from waking up the system unnecessarily.
  */
 bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
 {
        struct device *dev = &pci_dev->dev;
 
        if (!pm_runtime_suspended(dev)
-           || (device_can_wakeup(dev) && !device_may_wakeup(dev))
+           || pci_target_state(pci_dev) != pci_dev->current_state
            || platform_pci_need_resume(pci_dev))
                return false;
 
-       return pci_target_state(pci_dev) == pci_dev->current_state;
+       /*
+        * At this point the device is good to go unless it's been configured
+        * to generate PME at the runtime suspend time, but it is not supposed
+        * to wake up the system.  In that case, simply disable PME for it
+        * (it will have to be re-enabled on exit from system resume).
+        *
+        * If the device's power state is D3cold and the platform check above
+        * hasn't triggered, the device's configuration is suitable and we don't
+        * need to manipulate it at all.
+        */
+       spin_lock_irq(&dev->power.lock);
+
+       if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold &&
+           !device_may_wakeup(dev))
+               __pci_pme_active(pci_dev, false);
+
+       spin_unlock_irq(&dev->power.lock);
+       return true;
+}
+
+/**
+ * pci_dev_complete_resume - Finalize resume from system sleep for a device.
+ * @pci_dev: Device to handle.
+ *
+ * If the device is runtime suspended and wakeup-capable, enable PME for it as
+ * it might have been disabled during the prepare phase of system suspend if
+ * the device was not configured for system wakeup.
+ */
+void pci_dev_complete_resume(struct pci_dev *pci_dev)
+{
+       struct device *dev = &pci_dev->dev;
+
+       if (!pci_dev_run_wake(pci_dev))
+               return;
+
+       spin_lock_irq(&dev->power.lock);
+
+       if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold)
+               __pci_pme_active(pci_dev, true);
+
+       spin_unlock_irq(&dev->power.lock);
 }
 
 void pci_config_pm_runtime_get(struct pci_dev *pdev)
index a1607331693ece030bbb3a8f08064f0f2887807e..fd2f03fa53f33a34977fc8713fd8cf6759cad2d5 100644 (file)
@@ -75,6 +75,7 @@ void pci_disable_enabled_device(struct pci_dev *dev);
 int pci_finish_runtime_suspend(struct pci_dev *dev);
 int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
 bool pci_dev_keep_suspended(struct pci_dev *dev);
+void pci_dev_complete_resume(struct pci_dev *pci_dev);
 void pci_config_pm_runtime_get(struct pci_dev *dev);
 void pci_config_pm_runtime_put(struct pci_dev *dev);
 void pci_pm_init(struct pci_dev *dev);
index 5153d1d69aee8e0472c21ec63ff393f6fb9b7682..9113876487edd43037038357726208dd828e9a2a 100644 (file)
@@ -207,7 +207,7 @@ struct pnp_protocol pnpacpi_protocol = {
 };
 EXPORT_SYMBOL(pnpacpi_protocol);
 
-static char *__init pnpacpi_get_id(struct acpi_device *device)
+static const char *__init pnpacpi_get_id(struct acpi_device *device)
 {
        struct acpi_hardware_id *id;
 
@@ -222,7 +222,7 @@ static char *__init pnpacpi_get_id(struct acpi_device *device)
 static int __init pnpacpi_add_device(struct acpi_device *device)
 {
        struct pnp_dev *dev;
-       char *pnpid;
+       const char *pnpid;
        struct acpi_hardware_id *id;
        int error;
 
index 2e300028f0f774d4662546ba0bd88cce32465cf2..80994566a1c8f7594fceb3fd323e90e922ab666b 100644 (file)
@@ -271,6 +271,7 @@ static const struct of_device_id rockchip_iodomain_match[] = {
        },
        { /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
 
 static int rockchip_iodomain_probe(struct platform_device *pdev)
 {
index 5efacd050c7d56682016d6097a466fca1261611b..cc97f0869791d371c85f7e21c0ca04e1e595ac23 100644 (file)
@@ -1102,6 +1102,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
        RAPL_CPU(0x4A, rapl_defaults_tng),/* Tangier */
        RAPL_CPU(0x56, rapl_defaults_core),/* Future Xeon */
        RAPL_CPU(0x5A, rapl_defaults_ann),/* Annidale */
+       RAPL_CPU(0X5C, rapl_defaults_core),/* Broxton */
        RAPL_CPU(0x5E, rapl_defaults_core),/* Skylake-H/S */
        RAPL_CPU(0x57, rapl_defaults_hsw_server),/* Knights Landing */
        {}
index 052aecf298935e8420fc5b6df0069992b5dc4e3b..abd087917f807e03a466337a0fcf26cfd3499243 100644 (file)
@@ -396,7 +396,6 @@ int __init dove_init_pmu(void)
 
                __pmu_domain_register(domain, np);
        }
-       pm_genpd_poweroff_unused();
 
        /* Loss of the interrupt controller is not a fatal error. */
        parent_irq = irq_of_parse_and_map(pmu->of_node, 0);
index 9f20eb4acaa6054ef2362ee5eeef4576beb6c88a..204f5819d464b6ec3c169d78b2ec9a30989be90e 100644 (file)
@@ -193,8 +193,9 @@ struct acpi_exception_info {
 #define AE_AML_ILLEGAL_ADDRESS          EXCEP_AML (0x0020)
 #define AE_AML_INFINITE_LOOP            EXCEP_AML (0x0021)
 #define AE_AML_UNINITIALIZED_NODE       EXCEP_AML (0x0022)
+#define AE_AML_TARGET_TYPE              EXCEP_AML (0x0023)
 
-#define AE_CODE_AML_MAX                 0x0022
+#define AE_CODE_AML_MAX                 0x0023
 
 /*
  * Internal exceptions used for control
@@ -358,7 +359,9 @@ static const struct acpi_exception_info acpi_gbl_exception_names_aml[] = {
        EXCEP_TXT("AE_AML_INFINITE_LOOP",
                  "An apparent infinite AML While loop, method was aborted"),
        EXCEP_TXT("AE_AML_UNINITIALIZED_NODE",
-                 "A namespace node is uninitialized or unresolved")
+                 "A namespace node is uninitialized or unresolved"),
+       EXCEP_TXT("AE_AML_TARGET_TYPE",
+                 "A target operand of an incorrect type was encountered")
 };
 
 static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = {
index 5ba8fb64f664ecea523f21034ad3c8f7d3a47e13..d11eff8a4efe95f92d8e75a18498017709ca096f 100644 (file)
@@ -129,7 +129,7 @@ static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
 struct acpi_scan_handler {
        const struct acpi_device_id *ids;
        struct list_head list_node;
-       bool (*match)(char *idstr, const struct acpi_device_id **matchid);
+       bool (*match)(const char *idstr, const struct acpi_device_id **matchid);
        int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
        void (*detach)(struct acpi_device *dev);
        void (*bind)(struct device *phys_dev);
@@ -227,7 +227,7 @@ typedef char acpi_device_class[20];
 
 struct acpi_hardware_id {
        struct list_head list;
-       char *id;
+       const char *id;
 };
 
 struct acpi_pnp_type {
@@ -343,6 +343,7 @@ struct acpi_device_data {
        const union acpi_object *pointer;
        const union acpi_object *properties;
        const union acpi_object *of_compatible;
+       struct list_head subnodes;
 };
 
 struct acpi_gpio_mapping;
@@ -378,6 +379,17 @@ struct acpi_device {
        void (*remove)(struct acpi_device *);
 };
 
+/* Non-device subnode */
+struct acpi_data_node {
+       const char *name;
+       acpi_handle handle;
+       struct fwnode_handle fwnode;
+       struct acpi_device_data data;
+       struct list_head sibling;
+       struct kobject kobj;
+       struct completion kobj_done;
+};
+
 static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
 {
        bool ret = false;
@@ -412,16 +424,33 @@ static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
 }
 
 static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+       return fwnode && (fwnode->type == FWNODE_ACPI
+               || fwnode->type == FWNODE_ACPI_DATA);
+}
+
+static inline bool is_acpi_device_node(struct fwnode_handle *fwnode)
 {
        return fwnode && fwnode->type == FWNODE_ACPI;
 }
 
-static inline struct acpi_device *to_acpi_node(struct fwnode_handle *fwnode)
+static inline struct acpi_device *to_acpi_device_node(struct fwnode_handle *fwnode)
 {
-       return is_acpi_node(fwnode) ?
+       return is_acpi_device_node(fwnode) ?
                container_of(fwnode, struct acpi_device, fwnode) : NULL;
 }
 
+static inline bool is_acpi_data_node(struct fwnode_handle *fwnode)
+{
+       return fwnode && fwnode->type == FWNODE_ACPI_DATA;
+}
+
+static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwnode)
+{
+       return is_acpi_data_node(fwnode) ?
+               container_of(fwnode, struct acpi_data_node, fwnode) : NULL;
+}
+
 static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
 {
        return &adev->fwnode;
index a54ad1cc990c6b53d9e9b7a2f7283f2101f923ff..fbc2baf2b9dc98ac6f7195decd71b27aeac4076d 100644 (file)
@@ -55,7 +55,8 @@ typedef enum {
        OSL_GLOBAL_LOCK_HANDLER,
        OSL_NOTIFY_HANDLER,
        OSL_GPE_HANDLER,
-       OSL_DEBUGGER_THREAD,
+       OSL_DEBUGGER_MAIN_THREAD,
+       OSL_DEBUGGER_EXEC_THREAD,
        OSL_EC_POLL_HANDLER,
        OSL_EC_BURST_HANDLER
 } acpi_execute_type;
index c33eeabde1602ecb967df2b1c131a58cda32dc1e..3aaaa8630735c187d19943467f3242c1e0c9388a 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20150818
+#define ACPI_CA_VERSION                 0x20150930
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -393,15 +393,11 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_terminate(void))
  */
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_subsystem_status(void))
-#endif
 
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                            acpi_get_system_info(struct acpi_buffer
                                                 *ret_buffer))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_get_statistics(struct acpi_statistics *stats))
 ACPI_EXTERNAL_RETURN_PTR(const char
@@ -625,11 +621,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                                                               space_id,
                                                               acpi_adr_space_handler
                                                               handler))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_install_exception_handler
                             (acpi_exception_handler handler))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_install_interface_handler
                             (acpi_interface_handler handler))
@@ -750,12 +744,10 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_get_current_resources(acpi_handle device,
                                                        struct acpi_buffer
                                                        *ret_buffer))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_get_possible_resources(acpi_handle device,
                                                         struct acpi_buffer
                                                         *ret_buffer))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                             acpi_get_event_resources(acpi_handle device_handle,
                                                      struct acpi_buffer
@@ -844,7 +836,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 /*
  * ACPI Timer interfaces
  */
-#ifdef ACPI_FUTURE_USAGE
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
                                acpi_get_timer_resolution(u32 *resolution))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer(u32 *ticks))
@@ -853,7 +844,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
                                acpi_get_timer_duration(u32 start_ticks,
                                                        u32 end_ticks,
                                                        u32 *time_elapsed))
-#endif                         /* ACPI_FUTURE_USAGE */
 
 /*
  * Error/Warning output
@@ -939,4 +929,6 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                                               void **data,
                                               void (*callback)(void *)))
 
+void acpi_set_debugger_thread_id(acpi_thread_id thread_id);
+
 #endif                         /* __ACXFACE_H__ */
index fcd570999f354247c9dbba73163797ff38cbd1a6..1bb979e3e3f53b3bce69f348436e6c3a44a38d91 100644 (file)
@@ -1012,7 +1012,7 @@ struct acpi_nfit_memory_map {
 #define ACPI_NFIT_MEM_SAVE_FAILED       (1)    /* 00: Last SAVE to Memory Device failed */
 #define ACPI_NFIT_MEM_RESTORE_FAILED    (1<<1) /* 01: Last RESTORE from Memory Device failed */
 #define ACPI_NFIT_MEM_FLUSH_FAILED      (1<<2) /* 02: Platform flush failed */
-#define ACPI_NFIT_MEM_ARMED             (1<<3) /* 03: Memory Device observed to be not armed */
+#define ACPI_NFIT_MEM_NOT_ARMED         (1<<3) /* 03: Memory Device is not armed */
 #define ACPI_NFIT_MEM_HEALTH_OBSERVED   (1<<4) /* 04: Memory Device observed SMART/health events */
 #define ACPI_NFIT_MEM_HEALTH_ENABLED    (1<<5) /* 05: SMART/health events enabled */
 
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
new file mode 100644 (file)
index 0000000..717a298
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * CPPC (Collaborative Processor Performance Control) methods used
+ * by CPUfreq drivers.
+ *
+ * (C) Copyright 2014, 2015 Linaro Ltd.
+ * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef _CPPC_ACPI_H
+#define _CPPC_ACPI_H
+
+#include <linux/acpi.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
+#include <linux/types.h>
+
+#include <acpi/processor.h>
+
+/* Only support CPPCv2 for now. */
+#define CPPC_NUM_ENT   21
+#define CPPC_REV       2
+
+#define PCC_CMD_COMPLETE 1
+#define MAX_CPC_REG_ENT 19
+
+/* CPPC specific PCC commands. */
+#define        CMD_READ 0
+#define        CMD_WRITE 1
+
+/* Each register has the folowing format. */
+struct cpc_reg {
+       u8 descriptor;
+       u16 length;
+       u8 space_id;
+       u8 bit_width;
+       u8 bit_offset;
+       u8 access_width;
+       u64 __iomem address;
+} __packed;
+
+/*
+ * Each entry in the CPC table is either
+ * of type ACPI_TYPE_BUFFER or
+ * ACPI_TYPE_INTEGER.
+ */
+struct cpc_register_resource {
+       acpi_object_type type;
+       union {
+               struct cpc_reg reg;
+               u64 int_value;
+       } cpc_entry;
+};
+
+/* Container to hold the CPC details for each CPU */
+struct cpc_desc {
+       int num_entries;
+       int version;
+       int cpu_id;
+       struct cpc_register_resource cpc_regs[MAX_CPC_REG_ENT];
+       struct acpi_psd_package domain_info;
+};
+
+/* These are indexes into the per-cpu cpc_regs[]. Order is important. */
+enum cppc_regs {
+       HIGHEST_PERF,
+       NOMINAL_PERF,
+       LOW_NON_LINEAR_PERF,
+       LOWEST_PERF,
+       GUARANTEED_PERF,
+       DESIRED_PERF,
+       MIN_PERF,
+       MAX_PERF,
+       PERF_REDUC_TOLERANCE,
+       TIME_WINDOW,
+       CTR_WRAP_TIME,
+       REFERENCE_CTR,
+       DELIVERED_CTR,
+       PERF_LIMITED,
+       ENABLE,
+       AUTO_SEL_ENABLE,
+       AUTO_ACT_WINDOW,
+       ENERGY_PERF,
+       REFERENCE_PERF,
+};
+
+/*
+ * Categorization of registers as described
+ * in the ACPI v.5.1 spec.
+ * XXX: Only filling up ones which are used by governors
+ * today.
+ */
+struct cppc_perf_caps {
+       u32 highest_perf;
+       u32 nominal_perf;
+       u32 reference_perf;
+       u32 lowest_perf;
+};
+
+struct cppc_perf_ctrls {
+       u32 max_perf;
+       u32 min_perf;
+       u32 desired_perf;
+};
+
+struct cppc_perf_fb_ctrs {
+       u64 reference;
+       u64 prev_reference;
+       u64 delivered;
+       u64 prev_delivered;
+};
+
+/* Per CPU container for runtime CPPC management. */
+struct cpudata {
+       int cpu;
+       struct cppc_perf_caps perf_caps;
+       struct cppc_perf_ctrls perf_ctrls;
+       struct cppc_perf_fb_ctrs perf_fb_ctrs;
+       struct cpufreq_policy *cur_policy;
+       unsigned int shared_type;
+       cpumask_var_t shared_cpu_map;
+};
+
+extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
+extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
+extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
+extern int acpi_get_psd_map(struct cpudata **);
+
+/* Methods to interact with the PCC mailbox controller. */
+extern struct mbox_chan *
+       pcc_mbox_request_channel(struct mbox_client *, unsigned int);
+extern int mbox_send_message(struct mbox_chan *chan, void *mssg);
+
+#endif /* _CPPC_ACPI_H*/
index ec00e2bb029e6258daa3b0e8db8aa1061fabbc2c..056f245ad0380171b0de8adad7b89324ecbb29b0 100644 (file)
 
 #ifdef ACPI_LIBRARY
 #define ACPI_USE_LOCAL_CACHE
-#define ACPI_FUTURE_USAGE
+#define ACPI_FULL_DEBUG
 #endif
 
 /* Common for all ACPICA applications */
  * multi-threaded if ACPI_APPLICATION is not set.
  */
 #ifndef DEBUGGER_THREADING
-#ifdef ACPI_APPLICATION
-#define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
+#if !defined (ACPI_APPLICATION) || defined (ACPI_EXEC_APP)
+#define DEBUGGER_THREADING          DEBUGGER_MULTI_THREADED
 
 #else
-#define DEBUGGER_THREADING          DEBUGGER_MULTI_THREADED
+#define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
 #endif
 #endif                         /* !DEBUGGER_THREADING */
 
index 74ba46c8157a6f13098d27bd2338b8c8bf7db93f..323e5daece54999684144620cc644e4b64e1c707 100644 (file)
 
 #define ACPI_USE_SYSTEM_INTTYPES
 
-/* Compile for reduced hardware mode only with this kernel config */
+/* Kernel specific ACPICA configuration */
 
 #ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY
 #define ACPI_REDUCED_HARDWARE 1
 #endif
 
+#ifdef CONFIG_ACPI_DEBUGGER
+#define ACPI_DEBUGGER
+#endif
+
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
  * OSL interfaces used by utilities
  */
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address
index acedc3f026de7bd6e3a8a8fce834000e97efdcdc..fd6d70fe1219c35b12b65902759185e6bcbaa9cd 100644 (file)
@@ -124,6 +124,11 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
                lock ? AE_OK : AE_NO_MEMORY; \
        })
 
+static inline u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+       return TRUE;
+}
+
 /*
  * OSL interfaces added by Linux
  */
index ff5f135f16b139e5fb04096a8a28d8103d72d2c5..07fb100bcc688ddc1835b958ac430182ee699128 100644 (file)
@@ -311,6 +311,20 @@ phys_cpuid_t acpi_get_phys_id(acpi_handle, int type, u32 acpi_id);
 int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id);
 int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
 
+#ifdef CONFIG_ACPI_CPPC_LIB
+extern int acpi_cppc_processor_probe(struct acpi_processor *pr);
+extern void acpi_cppc_processor_exit(struct acpi_processor *pr);
+#else
+static inline int acpi_cppc_processor_probe(struct acpi_processor *pr)
+{
+       return 0;
+}
+static inline void acpi_cppc_processor_exit(struct acpi_processor *pr)
+{
+       return;
+}
+#endif /* CONFIG_ACPI_CPPC_LIB */
+
 /* in processor_pdc.c */
 void acpi_processor_set_pdc(acpi_handle handle);
 
index 1781e54ea6d30791796c450df64240dff720fbbf..c4bd0e2c173c011e37f6eef7acfb9bc3920fcca6 100644 (file)
 #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
 #define EARLYCON_OF_TABLES()   OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
 
+#ifdef CONFIG_ACPI
+#define ACPI_PROBE_TABLE(name)                                         \
+       . = ALIGN(8);                                                   \
+       VMLINUX_SYMBOL(__##name##_acpi_probe_table) = .;                \
+       *(__##name##_acpi_probe_table)                                  \
+       VMLINUX_SYMBOL(__##name##_acpi_probe_table_end) = .;
+#else
+#define ACPI_PROBE_TABLE(name)
+#endif
+
 #define KERNEL_DTB()                                                   \
        STRUCT_ALIGN();                                                 \
        VMLINUX_SYMBOL(__dtb_start) = .;                                \
        CPUIDLE_METHOD_OF_TABLES()                                      \
        KERNEL_DTB()                                                    \
        IRQCHIP_OF_MATCH_TABLE()                                        \
+       ACPI_PROBE_TABLE(irqchip)                                       \
+       ACPI_PROBE_TABLE(clksrc)                                        \
        EARLYCON_TABLE()                                                \
        EARLYCON_OF_TABLES()
 
index 55af199f8aaf73fef834d242442c5cffc6a089c9..ebfac2fe0c813bea9d98d01e8dc4f244e1bd97d4 100644 (file)
@@ -49,7 +49,7 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
        return adev ? adev->handle : NULL;
 }
 
-#define ACPI_COMPANION(dev)            to_acpi_node((dev)->fwnode)
+#define ACPI_COMPANION(dev)            to_acpi_device_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))
@@ -69,7 +69,7 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
 
 static inline bool has_acpi_companion(struct device *dev)
 {
-       return is_acpi_node(dev->fwnode);
+       return is_acpi_device_node(dev->fwnode);
 }
 
 static inline void acpi_preset_companion(struct device *dev,
@@ -131,6 +131,12 @@ static inline void acpi_initrd_override(void *data, size_t size)
                (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
                ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
 
+struct acpi_subtable_proc {
+       int id;
+       acpi_tbl_entry_handler handler;
+       int count;
+};
+
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 void __acpi_unmap_table(char *map, unsigned long size);
 int early_acpi_boot_init(void);
@@ -146,9 +152,16 @@ int __init acpi_parse_entries(char *id, unsigned long table_size,
                              struct acpi_table_header *table_header,
                              int entry_id, unsigned int max_entries);
 int __init acpi_table_parse_entries(char *id, unsigned long table_size,
-                                   int entry_id,
-                                   acpi_tbl_entry_handler handler,
-                                   unsigned int max_entries);
+                             int entry_id,
+                             acpi_tbl_entry_handler handler,
+                             unsigned int max_entries);
+int __init acpi_table_parse_entries(char *id, unsigned long table_size,
+                             int entry_id,
+                             acpi_tbl_entry_handler handler,
+                             unsigned int max_entries);
+int __init acpi_table_parse_entries_array(char *id, unsigned long table_size,
+                             struct acpi_subtable_proc *proc, int proc_num,
+                             unsigned int max_entries);
 int acpi_table_parse_madt(enum acpi_madt_type id,
                          acpi_tbl_entry_handler handler,
                          unsigned int max_entries);
@@ -193,6 +206,12 @@ int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base);
 void acpi_irq_stats_init(void);
 extern u32 acpi_irq_handled;
 extern u32 acpi_irq_not_handled;
+extern unsigned int acpi_sci_irq;
+#define INVALID_ACPI_IRQ       ((unsigned)-1)
+static inline bool acpi_sci_irq_valid(void)
+{
+       return acpi_sci_irq != INVALID_ACPI_IRQ;
+}
 
 extern int sbf_port;
 extern unsigned long acpi_realmode_flags;
@@ -465,7 +484,22 @@ static inline bool is_acpi_node(struct fwnode_handle *fwnode)
        return false;
 }
 
-static inline struct acpi_device *to_acpi_node(struct fwnode_handle *fwnode)
+static inline bool is_acpi_device_node(struct fwnode_handle *fwnode)
+{
+       return false;
+}
+
+static inline struct acpi_device *to_acpi_device_node(struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
+static inline bool is_acpi_data_node(struct fwnode_handle *fwnode)
+{
+       return false;
+}
+
+static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwnode)
 {
        return NULL;
 }
@@ -752,22 +786,76 @@ struct acpi_reference_args {
 #ifdef CONFIG_ACPI
 int acpi_dev_get_property(struct acpi_device *adev, const char *name,
                          acpi_object_type type, const union acpi_object **obj);
-int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
-                               acpi_object_type type,
-                               const union acpi_object **obj);
-int acpi_dev_get_property_reference(struct acpi_device *adev,
-                                   const char *name, size_t index,
-                                   struct acpi_reference_args *args);
-
-int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
-                     void **valptr);
+int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
+                                    const char *name, size_t index,
+                                    struct acpi_reference_args *args);
+
+int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
+                      void **valptr);
 int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
                              enum dev_prop_type proptype, void *val);
+int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
+                       enum dev_prop_type proptype, void *val, size_t nval);
 int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
                       enum dev_prop_type proptype, void *val, size_t nval);
 
-struct acpi_device *acpi_get_next_child(struct device *dev,
-                                       struct acpi_device *child);
+struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+                                           struct fwnode_handle *subnode);
+
+struct acpi_probe_entry;
+typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
+                                                struct acpi_probe_entry *);
+
+#define ACPI_TABLE_ID_LEN      5
+
+/**
+ * struct acpi_probe_entry - boot-time probing entry
+ * @id:                        ACPI table name
+ * @type:              Optional subtable type to match
+ *                     (if @id contains subtables)
+ * @subtable_valid:    Optional callback to check the validity of
+ *                     the subtable
+ * @probe_table:       Callback to the driver being probed when table
+ *                     match is successful
+ * @probe_subtbl:      Callback to the driver being probed when table and
+ *                     subtable match (and optional callback is successful)
+ * @driver_data:       Sideband data provided back to the driver
+ */
+struct acpi_probe_entry {
+       __u8 id[ACPI_TABLE_ID_LEN];
+       __u8 type;
+       acpi_probe_entry_validate_subtbl subtable_valid;
+       union {
+               acpi_tbl_table_handler probe_table;
+               acpi_tbl_entry_handler probe_subtbl;
+       };
+       kernel_ulong_t driver_data;
+};
+
+#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn)     \
+       static const struct acpi_probe_entry __acpi_probe_##name        \
+               __used __section(__##table##_acpi_probe_table)          \
+                = {                                                    \
+                       .id = table_id,                                 \
+                       .type = subtable,                               \
+                       .subtable_valid = valid,                        \
+                       .probe_table = (acpi_tbl_table_handler)fn,      \
+                       .driver_data = data,                            \
+                  }
+
+#define ACPI_PROBE_TABLE(name)         __##name##_acpi_probe_table
+#define ACPI_PROBE_TABLE_END(name)     __##name##_acpi_probe_table_end
+
+int __acpi_probe_device_table(struct acpi_probe_entry *start, int nr);
+
+#define acpi_probe_device_table(t)                                     \
+       ({                                                              \
+               extern struct acpi_probe_entry ACPI_PROBE_TABLE(t),     \
+                                              ACPI_PROBE_TABLE_END(t); \
+               __acpi_probe_device_table(&ACPI_PROBE_TABLE(t),         \
+                                         (&ACPI_PROBE_TABLE_END(t) -   \
+                                          &ACPI_PROBE_TABLE(t)));      \
+       })
 #else
 static inline int acpi_dev_get_property(struct acpi_device *adev,
                                        const char *name, acpi_object_type type,
@@ -775,16 +863,17 @@ static inline int acpi_dev_get_property(struct acpi_device *adev,
 {
        return -ENXIO;
 }
-static inline int acpi_dev_get_property_array(struct acpi_device *adev,
-                                             const char *name,
-                                             acpi_object_type type,
-                                             const union acpi_object **obj)
+
+static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
+                               const char *name, const char *cells_name,
+                               size_t index, struct acpi_reference_args *args)
 {
        return -ENXIO;
 }
-static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
-                               const char *name, const char *cells_name,
-                               size_t index, struct acpi_reference_args *args)
+
+static inline int acpi_node_prop_get(struct fwnode_handle *fwnode,
+                                    const char *propname,
+                                    void **valptr)
 {
        return -ENXIO;
 }
@@ -804,6 +893,14 @@ static inline int acpi_dev_prop_read_single(struct acpi_device *adev,
        return -ENXIO;
 }
 
+static inline int acpi_node_prop_read(struct fwnode_handle *fwnode,
+                                     const char *propname,
+                                     enum dev_prop_type proptype,
+                                     void *val, size_t nval)
+{
+       return -ENXIO;
+}
+
 static inline int acpi_dev_prop_read(struct acpi_device *adev,
                                     const char *propname,
                                     enum dev_prop_type proptype,
@@ -812,12 +909,22 @@ static inline int acpi_dev_prop_read(struct acpi_device *adev,
        return -ENXIO;
 }
 
-static inline struct acpi_device *acpi_get_next_child(struct device *dev,
-                                                     struct acpi_device *child)
+static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+                                               struct fwnode_handle *subnode)
 {
        return NULL;
 }
 
+#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, validate, data, fn) \
+       static const void * __acpi_table_##name[]                       \
+               __attribute__((unused))                                 \
+                = { (void *) table_id,                                 \
+                    (void *) subtable,                                 \
+                    (void *) valid,                                    \
+                    (void *) fn,                                       \
+                    (void *) data }
+
+#define acpi_probe_device_table(t)     ({ int __r = 0; __r;})
 #endif
 
 #endif /*_LINUX_ACPI_H*/
diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h
deleted file mode 100644 (file)
index f10c872..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _LINUX_ACPI_IRQ_H
-#define _LINUX_ACPI_IRQ_H
-
-#include <linux/irq.h>
-
-#ifndef acpi_irq_init
-static inline void acpi_irq_init(void) { }
-#endif
-
-#endif /* _LINUX_ACPI_IRQ_H */
index 278dd279a7a8035e8be073a9664ea88f7357984a..7784b597e9592b0ea0a32d661a0068cf9a8e2137 100644 (file)
@@ -246,16 +246,13 @@ extern int clocksource_i8253_init(void);
 #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
        OF_DECLARE_1(clksrc, name, compat, fn)
 
-#ifdef CONFIG_CLKSRC_OF
-extern void clocksource_of_init(void);
+#ifdef CONFIG_CLKSRC_PROBE
+extern void clocksource_probe(void);
 #else
-static inline void clocksource_of_init(void) {}
+static inline void clocksource_probe(void) {}
 #endif
 
-#ifdef CONFIG_ACPI
-void acpi_generic_timer_init(void);
-#else
-static inline void acpi_generic_timer_init(void) { }
-#endif
+#define CLOCKSOURCE_ACPI_DECLARE(name, table_id, fn)           \
+       ACPI_DECLARE_PROBE_ENTRY(clksrc, name, table_id, 0, NULL, 0, fn)
 
 #endif /* _LINUX_CLOCKSOURCE_H */
index dca22de98d948480141c5806680ef167b35a7555..ef4c5b1a860f5c610c0ee4646aa2b729aa81f71a 100644 (file)
@@ -65,7 +65,6 @@ struct cpufreq_policy {
        unsigned int            shared_type; /* ACPI: ANY or ALL affected CPUs
                                                should set cpufreq */
        unsigned int            cpu;    /* cpu managing this policy, must be online */
-       unsigned int            kobj_cpu; /* cpu managing sysfs files, can be offline */
 
        struct clk              *clk;
        struct cpufreq_cpuinfo  cpuinfo;/* see above */
@@ -149,10 +148,6 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy)
 
 /* /sys/devices/system/cpu/cpufreq: entry point for global variables */
 extern struct kobject *cpufreq_global_kobject;
-int cpufreq_get_global_kobject(void);
-void cpufreq_put_global_kobject(void);
-int cpufreq_sysfs_create_file(const struct attribute *attr);
-void cpufreq_sysfs_remove_file(const struct attribute *attr);
 
 #ifdef CONFIG_CPU_FREQ
 unsigned int cpufreq_get(unsigned int cpu);
index 37ec668546ab21897393bcebc1ba548796db7994..8516717427906948a215c56fad35ab462a8cbfda 100644 (file)
@@ -16,6 +16,7 @@ enum fwnode_type {
        FWNODE_INVALID = 0,
        FWNODE_OF,
        FWNODE_ACPI,
+       FWNODE_ACPI_DATA,
        FWNODE_PDATA,
        FWNODE_IRQCHIP,
 };
index 388e3ae94f7a3b1c3c86d7ba45d6f9227ee31f0d..24bea087e7af8083b3c81596a289d70530c64285 100644 (file)
@@ -94,6 +94,7 @@ struct resource {
 /* PnP I/O specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_IO_16BIT_ADDR       (1<<0)
 #define IORESOURCE_IO_FIXED            (1<<1)
+#define IORESOURCE_IO_SPARSE           (1<<2)
 
 /* PCI ROM control bits (IORESOURCE_BITS) */
 #define IORESOURCE_ROM_ENABLE          (1<<0)  /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
index 638887376e582c83531ea663269ddfc1ef625a42..89c34b20067122f732073df0b3234dfab2a7fa48 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef _LINUX_IRQCHIP_H
 #define _LINUX_IRQCHIP_H
 
+#include <linux/acpi.h>
 #include <linux/of.h>
 
 /*
  */
 #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
 
+/*
+ * This macro must be used by the different irqchip drivers to declare
+ * the association between their version and their initialization function.
+ *
+ * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
+ * same file.
+ * @subtable: Subtable to be identified in MADT
+ * @validate: Function to be called on that subtable to check its validity.
+ *            Can be NULL.
+ * @data: data to be checked by the validate function.
+ * @fn: initialization function
+ */
+#define IRQCHIP_ACPI_DECLARE(name, subtable, validate, data, fn)       \
+       ACPI_DECLARE_PROBE_ENTRY(irqchip, name, ACPI_SIG_MADT,          \
+                                subtable, validate, data, fn)
+
 #ifdef CONFIG_IRQCHIP
 void irqchip_init(void);
 #else
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
deleted file mode 100644 (file)
index de3419e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2014, Linaro Ltd.
- *     Author: Tomasz Nowicki <tomasz.nowicki@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.
- */
-
-#ifndef ARM_GIC_ACPI_H_
-#define ARM_GIC_ACPI_H_
-
-#ifdef CONFIG_ACPI
-
-/*
- * Hard code here, we can not get memory size from MADT (but FDT does),
- * Actually no need to do that, because this size can be inferred
- * from GIC spec.
- */
-#define ACPI_GICV2_DIST_MEM_SIZE       (SZ_4K)
-#define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
-
-struct acpi_table_header;
-
-int gic_v2_acpi_init(struct acpi_table_header *table);
-void acpi_gic_init(void);
-#else
-static inline void acpi_gic_init(void) { }
-#endif
-
-#endif /* ARM_GIC_ACPI_H_ */
index a965efa52152ee27b38a7827588610802e4f6079..89ab0572dbc63cfe4375cdae9528809b3b0bdd62 100644 (file)
@@ -52,6 +52,30 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
        return ACPI_HANDLE(dev);
 }
 
+struct acpi_pci_root;
+struct acpi_pci_root_ops;
+
+struct acpi_pci_root_info {
+       struct acpi_pci_root            *root;
+       struct acpi_device              *bridge;
+       struct acpi_pci_root_ops        *ops;
+       struct list_head                resources;
+       char                            name[16];
+};
+
+struct acpi_pci_root_ops {
+       struct pci_ops *pci_ops;
+       int (*init_info)(struct acpi_pci_root_info *info);
+       void (*release_info)(struct acpi_pci_root_info *info);
+       int (*prepare_resources)(struct acpi_pci_root_info *info);
+};
+
+extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info);
+extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+                                           struct acpi_pci_root_ops *ops,
+                                           struct acpi_pci_root_info *info,
+                                           void *sd);
+
 void acpi_pci_add_bus(struct pci_bus *bus);
 void acpi_pci_remove_bus(struct pci_bus *bus);
 
index 35d599e7250d2d8c29defd0373ff25fed0b03467..528be6787796b52a405fbc0af8bf707c31d55192 100644 (file)
@@ -732,6 +732,7 @@ extern int pm_generic_poweroff_noirq(struct device *dev);
 extern int pm_generic_poweroff_late(struct device *dev);
 extern int pm_generic_poweroff(struct device *dev);
 extern void pm_generic_complete(struct device *dev);
+extern void pm_complete_with_resume_check(struct device *dev);
 
 #else /* !CONFIG_PM_SLEEP */
 
index b1cf7e797892b29dcce263c2a67a7a8201ee7bb2..ba4ced38efae0c9249a97ea57c0cccd1ac37e7f7 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/notifier.h>
-#include <linux/cpuidle.h>
 
 /* Defines used for the flags field in the struct generic_pm_domain */
 #define GENPD_FLAG_PM_CLK      (1U << 0) /* PM domain uses PM clk */
@@ -38,11 +37,6 @@ struct gpd_dev_ops {
        bool (*active_wakeup)(struct device *dev);
 };
 
-struct gpd_cpuidle_data {
-       unsigned int saved_exit_latency;
-       struct cpuidle_state *idle_state;
-};
-
 struct generic_pm_domain {
        struct dev_pm_domain domain;    /* PM domain operations */
        struct list_head gpd_list_node; /* Node in the global PM domains list */
@@ -53,7 +47,6 @@ struct generic_pm_domain {
        struct dev_power_governor *gov;
        struct work_struct power_off_work;
        const char *name;
-       unsigned int in_progress;       /* Number of devices being suspended now */
        atomic_t sd_count;      /* Number of subdomains with power "on" */
        enum gpd_status status; /* Current state of the domain */
        unsigned int device_count;      /* Number of devices */
@@ -68,7 +61,6 @@ struct generic_pm_domain {
        s64 max_off_time_ns;    /* Maximum allowed "suspended" time. */
        bool max_off_time_changed;
        bool cached_power_down_ok;
-       struct gpd_cpuidle_data *cpuidle_data;
        int (*attach_dev)(struct generic_pm_domain *domain,
                          struct device *dev);
        void (*detach_dev)(struct generic_pm_domain *domain,
@@ -89,10 +81,8 @@ struct gpd_link {
 };
 
 struct gpd_timing_data {
-       s64 stop_latency_ns;
-       s64 start_latency_ns;
-       s64 save_state_latency_ns;
-       s64 restore_state_latency_ns;
+       s64 suspend_latency_ns;
+       s64 resume_latency_ns;
        s64 effective_constraint_ns;
        bool constraint_changed;
        bool cached_stop_ok;
@@ -125,29 +115,15 @@ extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,
                                 struct device *dev,
                                 struct gpd_timing_data *td);
 
-extern int __pm_genpd_name_add_device(const char *domain_name,
-                                     struct device *dev,
-                                     struct gpd_timing_data *td);
-
 extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                                  struct device *dev);
 extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                  struct generic_pm_domain *new_subdomain);
-extern int pm_genpd_add_subdomain_names(const char *master_name,
-                                       const char *subdomain_name);
 extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
                                     struct generic_pm_domain *target);
-extern int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
-extern int pm_genpd_name_attach_cpuidle(const char *name, int state);
-extern int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd);
-extern int pm_genpd_name_detach_cpuidle(const char *name);
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
                          struct dev_power_governor *gov, bool is_off);
 
-extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
-extern int pm_genpd_name_poweron(const char *domain_name);
-extern void pm_genpd_poweroff_unused(void);
-
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
 #else
@@ -166,12 +142,6 @@ static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
 {
        return -ENOSYS;
 }
-static inline int __pm_genpd_name_add_device(const char *domain_name,
-                                            struct device *dev,
-                                            struct gpd_timing_data *td)
-{
-       return -ENOSYS;
-}
 static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                                         struct device *dev)
 {
@@ -182,45 +152,15 @@ static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 {
        return -ENOSYS;
 }
-static inline int pm_genpd_add_subdomain_names(const char *master_name,
-                                              const char *subdomain_name)
-{
-       return -ENOSYS;
-}
 static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
                                            struct generic_pm_domain *target)
 {
        return -ENOSYS;
 }
-static inline int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
-{
-       return -ENOSYS;
-}
-static inline int pm_genpd_name_attach_cpuidle(const char *name, int state)
-{
-       return -ENOSYS;
-}
-static inline int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
-{
-       return -ENOSYS;
-}
-static inline int pm_genpd_name_detach_cpuidle(const char *name)
-{
-       return -ENOSYS;
-}
 static inline void pm_genpd_init(struct generic_pm_domain *genpd,
                                 struct dev_power_governor *gov, bool is_off)
 {
 }
-static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
-{
-       return -ENOSYS;
-}
-static inline int pm_genpd_name_poweron(const char *domain_name)
-{
-       return -ENOSYS;
-}
-static inline void pm_genpd_poweroff_unused(void) {}
 #endif
 
 static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
@@ -229,12 +169,6 @@ static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
        return __pm_genpd_add_device(genpd, dev, NULL);
 }
 
-static inline int pm_genpd_name_add_device(const char *domain_name,
-                                          struct device *dev)
-{
-       return __pm_genpd_name_add_device(domain_name, dev, NULL);
-}
-
 #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP
 extern void pm_genpd_syscore_poweroff(struct device *dev);
 extern void pm_genpd_syscore_poweron(struct device *dev);
index e817722ee3f018a72e9784e5c2269a3f51017b12..9a2e50337af9fd233656b8fb6f06a91c10b2e7bf 100644 (file)
@@ -132,37 +132,37 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(
 #endif         /* CONFIG_PM_OPP */
 
 #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
-int of_init_opp_table(struct device *dev);
-void of_free_opp_table(struct device *dev);
-int of_cpumask_init_opp_table(cpumask_var_t cpumask);
-void of_cpumask_free_opp_table(cpumask_var_t cpumask);
-int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask);
-int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask);
+int dev_pm_opp_of_add_table(struct device *dev);
+void dev_pm_opp_of_remove_table(struct device *dev);
+int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask);
+void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask);
+int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask);
+int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask);
 #else
-static inline int of_init_opp_table(struct device *dev)
+static inline int dev_pm_opp_of_add_table(struct device *dev)
 {
        return -EINVAL;
 }
 
-static inline void of_free_opp_table(struct device *dev)
+static inline void dev_pm_opp_of_remove_table(struct device *dev)
 {
 }
 
-static inline int of_cpumask_init_opp_table(cpumask_var_t cpumask)
+static inline int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask)
 {
        return -ENOSYS;
 }
 
-static inline void of_cpumask_free_opp_table(cpumask_var_t cpumask)
+static inline void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask)
 {
 }
 
-static inline int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask)
+static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
 {
        return -ENOSYS;
 }
 
-static inline int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask)
+static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
 {
        return -ENOSYS;
 }
index a59c6ee566c2cf908ca7c6ec5512768e90d4a3b0..463de52fe8915486d2e2159bde7edf12834f8dcc 100644 (file)
@@ -40,6 +40,8 @@ int device_property_read_string_array(struct device *dev, const char *propname,
                                      const char **val, size_t nval);
 int device_property_read_string(struct device *dev, const char *propname,
                                const char **val);
+int device_property_match_string(struct device *dev,
+                                const char *propname, const char *string);
 
 bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
 int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
@@ -59,6 +61,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
                                      size_t nval);
 int fwnode_property_read_string(struct fwnode_handle *fwnode,
                                const char *propname, const char **val);
+int fwnode_property_match_string(struct fwnode_handle *fwnode,
+                                const char *propname, const char *string);
 
 struct fwnode_handle *device_get_next_child_node(struct device *dev,
                                                 struct fwnode_handle *child);
index 5efe743ce1e88fc544cd4d98b2100861f1774105..8b6ec7ef0854e0f51fd94e38dbf7b831c9015f6c 100644 (file)
@@ -202,6 +202,36 @@ struct platform_freeze_ops {
 extern void suspend_set_ops(const struct platform_suspend_ops *ops);
 extern int suspend_valid_only_mem(suspend_state_t state);
 
+extern unsigned int pm_suspend_global_flags;
+
+#define PM_SUSPEND_FLAG_FW_SUSPEND     (1 << 0)
+#define PM_SUSPEND_FLAG_FW_RESUME      (1 << 1)
+
+static inline void pm_suspend_clear_flags(void)
+{
+       pm_suspend_global_flags = 0;
+}
+
+static inline void pm_set_suspend_via_firmware(void)
+{
+       pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_SUSPEND;
+}
+
+static inline void pm_set_resume_via_firmware(void)
+{
+       pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
+}
+
+static inline bool pm_suspend_via_firmware(void)
+{
+       return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND);
+}
+
+static inline bool pm_resume_via_firmware(void)
+{
+       return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
+}
+
 /* Suspend-to-idle state machnine. */
 enum freeze_state {
        FREEZE_STATE_NONE,      /* Not suspended/suspending. */
@@ -241,6 +271,12 @@ extern int pm_suspend(suspend_state_t state);
 #else /* !CONFIG_SUSPEND */
 #define suspend_valid_only_mem NULL
 
+static inline void pm_suspend_clear_flags(void) {}
+static inline void pm_set_suspend_via_firmware(void) {}
+static inline void pm_set_resume_via_firmware(void) {}
+static inline bool pm_suspend_via_firmware(void) { return false; }
+static inline bool pm_resume_via_firmware(void) { return false; }
+
 static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
 static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
 static inline bool idle_should_freeze(void) { return false; }
@@ -387,10 +423,12 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
 
 /* drivers/base/power/wakeup.c */
 extern bool events_check_enabled;
+extern unsigned int pm_wakeup_irq;
 
 extern bool pm_wakeup_pending(void);
 extern void pm_system_wakeup(void);
 extern void pm_wakeup_clear(void);
+extern void pm_system_irq_wakeup(unsigned int irq_number);
 extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
 extern void pm_wakep_autosleep_enabled(bool set);
@@ -440,6 +478,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 static inline bool pm_wakeup_pending(void) { return false; }
 static inline void pm_system_wakeup(void) {}
 static inline void pm_wakeup_clear(void) {}
+static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
 
 static inline void lock_system_sleep(void) {}
 static inline void unlock_system_sleep(void) {}
index 21c62617a35a6dae316b22221b3b4896317faedd..e80c4400118ae7a8e3f09476964260490fccf01a 100644 (file)
@@ -21,7 +21,7 @@ bool irq_pm_check_wakeup(struct irq_desc *desc)
                desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
                desc->depth++;
                irq_disable(desc);
-               pm_system_wakeup();
+               pm_system_irq_wakeup(irq_desc_get_irq(desc));
                return true;
        }
        return false;
index 690f78f210f2cf4ec9436c9f37a3bbf5eb876397..b7342a24f559211934fb90db21a4a06d5479b21a 100644 (file)
@@ -733,7 +733,7 @@ int hibernate(void)
  * contents of memory is restored from the saved image.
  *
  * If this is successful, control reappears in the restored target kernel in
- * hibernation_snaphot() which returns to hibernate().  Otherwise, the routine
+ * hibernation_snapshot() which returns to hibernate().  Otherwise, the routine
  * attempts to recover gracefully and make the kernel return to the normal mode
  * of operation.
  */
index 63d395b5df9305b0033e6e294e209bf101e0937b..b2dd4d999900a26edd9cd26fb952b84b98ee411f 100644 (file)
@@ -272,6 +272,22 @@ static inline void pm_print_times_init(void)
 {
        pm_print_times_enabled = !!initcall_debug;
 }
+
+static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       char *buf)
+{
+       return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
+}
+
+static ssize_t pm_wakeup_irq_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t n)
+{
+       return -EINVAL;
+}
+power_attr(pm_wakeup_irq);
+
 #else /* !CONFIG_PM_SLEEP_DEBUG */
 static inline void pm_print_times_init(void) {}
 #endif /* CONFIG_PM_SLEEP_DEBUG */
@@ -604,6 +620,7 @@ static struct attribute * g[] = {
 #endif
 #ifdef CONFIG_PM_SLEEP_DEBUG
        &pm_print_times_attr.attr,
+       &pm_wakeup_irq_attr.attr,
 #endif
 #endif
 #ifdef CONFIG_FREEZER
index 7e4cda4a8dd9d5386bc657ef0c3a37851417a637..f9fe133c13e24de8e91f4ea81abebe6c58a3fd23 100644 (file)
@@ -35,6 +35,9 @@
 const char *pm_labels[] = { "mem", "standby", "freeze", NULL };
 const char *pm_states[PM_SUSPEND_MAX];
 
+unsigned int pm_suspend_global_flags;
+EXPORT_SYMBOL_GPL(pm_suspend_global_flags);
+
 static const struct platform_suspend_ops *suspend_ops;
 static const struct platform_freeze_ops *freeze_ops;
 static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
@@ -493,6 +496,7 @@ static int enter_state(suspend_state_t state)
 #endif
 
        pr_debug("PM: Preparing system for sleep (%s)\n", pm_states[state]);
+       pm_suspend_clear_flags();
        error = suspend_prepare(state);
        if (error)
                goto Unlock;
index a37f9702b2a90433978f4a6715919c4a9f8e11e6..a1c62de42a3bc479e04818df981885eb2e458a47 100644 (file)
@@ -150,7 +150,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
                strcat(filename, instance_str);
        }
 
-       strcat(filename, ACPI_TABLE_FILE_SUFFIX);
+       strcat(filename, FILE_SUFFIX_BINARY_TABLE);
 
        if (gbl_verbose_mode) {
                acpi_log_error