ACPI and power management updates for 3.14-rc1

- ACPI core changes to make it create a struct acpi_device object for every
    device represented in the ACPI tables during all namespace scans regardless
    of the current status of that device.  In accordance with this, ACPI hotplug
    operations will not delete those objects, unless the underlying ACPI tables
    go away.
 
  - On top of the above, new sysfs attribute for ACPI device objects allowing
    user space to check device status by triggering the execution of _STA for
    its ACPI object.  From Srinivas Pandruvada.
 
  - ACPI core hotplug changes reducing code duplication, integrating the
    PCI root hotplug with the core and reworking container hotplug.
 
  - ACPI core simplifications making it use ACPI_COMPANION() in the code
    "glueing" ACPI device objects to "physical" devices.
 
  - ACPICA update to upstream version 20131218.  This adds support for the
    DBG2 and PCCT tables to ACPICA, fixes some bugs and improves debug
    facilities.  From Bob Moore, Lv Zheng and Betty Dall.
 
  - Init code change to carry out the early ACPI initialization earlier.
    That should allow us to use ACPI during the timekeeping initialization
    and possibly to simplify the EFI initialization too.  From Chun-Yi Lee.
 
  - Clenups of the inclusions of ACPI headers in many places all over from
    Lv Zheng and Rashika Kheria (work in progress).
 
  - New helper for ACPI _DSM execution and rework of the code in drivers
    that uses _DSM to execute it via the new helper.  From Jiang Liu.
 
  - New Win8 OSI blacklist entries from Takashi Iwai.
 
  - Assorted ACPI fixes and cleanups from Al Stone, Emil Goode, Hanjun Guo,
    Lan Tianyu, Masanari Iida, Oliver Neukum, Prarit Bhargava, Rashika Kheria,
    Tang Chen, Zhang Rui.
 
  - intel_pstate driver updates, including proper Baytrail support, from
    Dirk Brandewie and intel_pstate documentation from Ramkumar Ramachandra.
 
  - Generic CPU boost ("turbo") support for cpufreq from Lukasz Majewski.
 
  - powernow-k6 cpufreq driver fixes from Mikulas Patocka.
 
  - cpufreq core fixes and cleanups from Viresh Kumar, Jane Li, Mark Brown.
 
  - Assorted cpufreq drivers fixes and cleanups from Anson Huang, John Tobias,
    Paul Bolle, Paul Walmsley, Sachin Kamat, Shawn Guo, Viresh Kumar.
 
  - cpuidle cleanups from Bartlomiej Zolnierkiewicz.
 
  - Support for hibernation APM events from Bin Shi.
 
  - Hibernation fix to avoid bringing up nonboot CPUs with ACPI EC disabled
    during thaw transitions from Bjørn Mork.
 
  - PM core fixes and cleanups from Ben Dooks, Leonardo Potenza, Ulf Hansson.
 
  - PNP subsystem fixes and cleanups from Dmitry Torokhov, Levente Kurusa,
    Rashika Kheria.
 
  - New tool for profiling system suspend from Todd E Brandt and a cpupower
    tool cleanup from One Thousand Gnomes.
 
 /
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJS3a1eAAoJEILEb/54YlRxnTgP/iGawvgjKWm6Qqp7WSIvd5gQ
 zZ6q75C6Pc/W2fq1+OzVGnpCF8WYFy+nFDAXOvUHjIXuoxSwFcuW5l4aMckgl/0a
 TXEWe9MJrCHHRfDApfFacCJ44U02bjJAD5vTyL/hKA+IHeinq4WCSojryYC+8jU0
 cBrUIV0aNH8r5JR2WJNAyv/U29rXsDUOu0I4qTqZ4YaZT6AignMjtLXn1e9AH1Pn
 DPZphTIo/HMnb+kgBOjt4snMk+ahVO9eCOxh/hH8ecnWExw9WynXoU5Nsna0tSZs
 ssyHC7BYexD3oYsG8D52cFUpp4FCsJ0nFQNa2kw0LY+0FBNay43LySisKYHZPXEs
 2WpESDv+/t7yhtnrvM+TtA7aBheKm2XMWGFSu/aERLE17jIidOkXKH5Y7ryYLNf/
 uyRKxNS0NcZWZ0G+/wuY02jQYNkfYz3k/nTr8BAUItRBjdporGIRNEnR9gPzgCUC
 uQhjXWMPulqubr8xbyefPWHTEzU2nvbXwTUWGjrBxSy8zkyy5arfqizUj+VG6afT
 NsboANoMHa9b+xdzigSFdA3nbVK6xBjtU6Ywntk9TIpODKF5NgfARx0H+oSH+Zrj
 32bMzgZtHw/lAbYsnQ9OnTY6AEWQYt6NMuVbTiLXrMHhM3nWwfg/XoN4nZqs6jPo
 IYvE6WhQZU6L6fptGHFC
 =dRf6
 -----END PGP SIGNATURE-----

Merge tag 'pm+acpi-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI and power management updates from Rafael Wysocki:
 "As far as the number of commits goes, the top spot belongs to ACPI
  this time with cpufreq in the second position and a handful of PM
  core, PNP and cpuidle updates.  They are fixes and cleanups mostly, as
  usual, with a couple of new features in the mix.

  The most visible change is probably that we will create struct
  acpi_device objects (visible in sysfs) for all devices represented in
  the ACPI tables regardless of their status and there will be a new
  sysfs attribute under those objects allowing user space to check that
  status via _STA.

  Consequently, ACPI device eject or generally hot-removal will not
  delete those objects, unless the table containing the corresponding
  namespace nodes is unloaded, which is extremely rare.  Also ACPI
  container hotplug will be handled quite a bit differently and cpufreq
  will support CPU boost ("turbo") generically and not only in the
  acpi-cpufreq driver.

  Specifics:

   - ACPI core changes to make it create a struct acpi_device object for
     every device represented in the ACPI tables during all namespace
     scans regardless of the current status of that device.  In
     accordance with this, ACPI hotplug operations will not delete those
     objects, unless the underlying ACPI tables go away.

   - On top of the above, new sysfs attribute for ACPI device objects
     allowing user space to check device status by triggering the
     execution of _STA for its ACPI object.  From Srinivas Pandruvada.

   - ACPI core hotplug changes reducing code duplication, integrating
     the PCI root hotplug with the core and reworking container hotplug.

   - ACPI core simplifications making it use ACPI_COMPANION() in the
     code "glueing" ACPI device objects to "physical" devices.

   - ACPICA update to upstream version 20131218.  This adds support for
     the DBG2 and PCCT tables to ACPICA, fixes some bugs and improves
     debug facilities.  From Bob Moore, Lv Zheng and Betty Dall.

   - Init code change to carry out the early ACPI initialization
     earlier.  That should allow us to use ACPI during the timekeeping
     initialization and possibly to simplify the EFI initialization too.
     From Chun-Yi Lee.

   - Clenups of the inclusions of ACPI headers in many places all over
     from Lv Zheng and Rashika Kheria (work in progress).

   - New helper for ACPI _DSM execution and rework of the code in
     drivers that uses _DSM to execute it via the new helper.  From
     Jiang Liu.

   - New Win8 OSI blacklist entries from Takashi Iwai.

   - Assorted ACPI fixes and cleanups from Al Stone, Emil Goode, Hanjun
     Guo, Lan Tianyu, Masanari Iida, Oliver Neukum, Prarit Bhargava,
     Rashika Kheria, Tang Chen, Zhang Rui.

   - intel_pstate driver updates, including proper Baytrail support,
     from Dirk Brandewie and intel_pstate documentation from Ramkumar
     Ramachandra.

   - Generic CPU boost ("turbo") support for cpufreq from Lukasz
     Majewski.

   - powernow-k6 cpufreq driver fixes from Mikulas Patocka.

   - cpufreq core fixes and cleanups from Viresh Kumar, Jane Li, Mark
     Brown.

   - Assorted cpufreq drivers fixes and cleanups from Anson Huang, John
     Tobias, Paul Bolle, Paul Walmsley, Sachin Kamat, Shawn Guo, Viresh
     Kumar.

   - cpuidle cleanups from Bartlomiej Zolnierkiewicz.

   - Support for hibernation APM events from Bin Shi.

   - Hibernation fix to avoid bringing up nonboot CPUs with ACPI EC
     disabled during thaw transitions from Bjørn Mork.

   - PM core fixes and cleanups from Ben Dooks, Leonardo Potenza, Ulf
     Hansson.

   - PNP subsystem fixes and cleanups from Dmitry Torokhov, Levente
     Kurusa, Rashika Kheria.

   - New tool for profiling system suspend from Todd E Brandt and a
     cpupower tool cleanup from One Thousand Gnomes"

* tag 'pm+acpi-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (153 commits)
  thermal: exynos: boost: Automatic enable/disable of BOOST feature (at Exynos4412)
  cpufreq: exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
  Documentation: cpufreq / boost: Update BOOST documentation
  cpufreq: exynos: Extend Exynos cpufreq driver to support boost
  cpufreq / boost: Kconfig: Support for software-managed BOOST
  acpi-cpufreq: Adjust the code to use the common boost attribute
  cpufreq: Add boost frequency support in core
  intel_pstate: Add trace point to report internal state.
  cpufreq: introduce cpufreq_generic_get() routine
  ARM: SA1100: Create dummy clk_get_rate() to avoid build failures
  cpufreq: stats: create sysfs entries when cpufreq_stats is a module
  cpufreq: stats: free table and remove sysfs entry in a single routine
  cpufreq: stats: remove hotplug notifiers
  cpufreq: stats: handle cpufreq_unregister_driver() and suspend/resume properly
  cpufreq: speedstep: remove unused speedstep_get_state
  platform: introduce OF style 'modalias' support for platform bus
  PM / tools: new tool for suspend/resume performance optimization
  ACPI: fix module autoloading for ACPI enumerated devices
  ACPI: add module autoloading support for ACPI enumerated devices
  ACPI: fix create_modalias() return value handling
  ...
This commit is contained in:
Linus Torvalds 2014-01-24 15:51:02 -08:00
commit 09da8dfa98
242 changed files with 4649 additions and 2749 deletions

View File

@ -200,3 +200,27 @@ Description: address and size of the percpu note.
note of cpu#.
crash_notes_size: size of the note of cpu#.
What: /sys/devices/system/cpu/intel_pstate/max_perf_pct
/sys/devices/system/cpu/intel_pstate/min_perf_pct
/sys/devices/system/cpu/intel_pstate/no_turbo
Date: February 2013
Contact: linux-pm@vger.kernel.org
Description: Parameters for the Intel P-state driver
Logic for selecting the current P-state in Intel
Sandybridge+ processors. The three knobs control
limits for the P-state that will be requested by the
driver.
max_perf_pct: limits the maximum P state that will be requested by
the driver stated as a percentage of the available performance.
min_perf_pct: limits the minimum P state that will be requested by
the driver stated as a percentage of the available performance.
no_turbo: limits the driver to selecting P states below the turbo
frequency range.
More details can be found in Documentation/cpu-freq/intel-pstate.txt

View File

@ -235,10 +235,6 @@ Wysocki <rafael.j.wysocki@intel.com>.
named object's type in the second column). In that case the object's
directory in sysfs will contain the 'path' attribute whose value is
the full path to the node from the namespace root.
struct acpi_device objects are created for the ACPI namespace nodes
whose _STA control methods return PRESENT or FUNCTIONING. The power
resource nodes or nodes without _STA are assumed to be both PRESENT
and FUNCTIONING.
F:
The struct acpi_device object is created for a fixed hardware
feature (as indicated by the fixed feature flag's name in the second
@ -340,7 +336,7 @@ Wysocki <rafael.j.wysocki@intel.com>.
| +-------------+-------+----------------+
| |
| | +- - - - - - - +- - - - - - +- - - - - - - -+
| +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
| +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
| | +- - - - - - - +- - - - - - +- - - - - - - -+
| |
| | +------------+------------+-----------------------+
@ -390,6 +386,3 @@ Wysocki <rafael.j.wysocki@intel.com>.
attribute (as described earlier in this document).
NOTE: N/A indicates the device object does not have the 'path' or the
'modalias' attribute.
NOTE: The PNP0C0D device listed above is highlighted (marked by "*")
to indicate it will be created only when its _STA methods return
PRESENT or FUNCTIONING.

View File

@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
budget. This is done without operating system control by a combination
of hardware and firmware.
budget. The decision about boost disable/enable is made either at hardware
(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
To allow the user to toggle the boosting functionality, the acpi-cpufreq
driver exports a sysfs knob to disable it. There is a file:
To allow the user to toggle the boosting functionality, the cpufreq core
driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
Reading the file is always supported, even if the processor does not
support boosting. In this case the file will be read-only and always
reads as "0". Explicitly changing the permissions and writing to that
file anyway will return EINVAL.
The file is exported only when cpufreq driver supports boosting.
Explicitly changing the permissions and writing to that file anyway will
return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
whole system (0) or will allow the hardware to boost at will (1).
whole system (0) or will allow the software or hardware to boost at will
(1).
Writing a "1" does not explicitly boost the system, but just allows the
CPU (and the firmware) to boost at their discretion. Some implementations
take external factors like the chip's temperature into account, so
boosting once does not necessarily mean that it will occur every time
even using the exact same software setup.
CPU to boost at their discretion. Some implementations take external
factors like the chip's temperature into account, so boosting once does
not necessarily mean that it will occur every time even using the exact
same software setup.
AMD legacy cpb switch

View File

@ -0,0 +1,40 @@
Intel P-state driver
--------------------
This driver implements a scaling driver with an internal governor for
Intel Core processors. The driver follows the same model as the
Transmeta scaling driver (longrun.c) and implements the setpolicy()
instead of target(). Scaling drivers that implement setpolicy() are
assumed to implement internal governors by the cpufreq core. All the
logic for selecting the current P state is contained within the
driver; no external governor is used by the cpufreq core.
Intel SandyBridge+ processors are supported.
New sysfs files for controlling P state selection have been added to
/sys/devices/system/cpu/intel_pstate/
max_perf_pct: limits the maximum P state that will be requested by
the driver stated as a percentage of the available performance.
min_perf_pct: limits the minimum P state that will be requested by
the driver stated as a percentage of the available performance.
no_turbo: limits the driver to selecting P states below the turbo
frequency range.
For contemporary Intel processors, the frequency is controlled by the
processor itself and the P-states exposed to software are related to
performance levels. The idea that frequency can be set to a single
frequency is fiction for Intel Core processors. Even if the scaling
driver selects a single P state the actual frequency the processor
will run at is selected by the processor itself.
New debugfs files have also been added to /sys/kernel/debug/pstate_snb/
deadband
d_gain_pct
i_gain_pct
p_gain_pct
sample_rate_ms
setpoint

View File

@ -343,6 +343,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
no: ACPI OperationRegions are not marked as reserved,
no further checks are performed.
acpi_no_memhotplug [ACPI] Disable memory hotplug. Useful for kdump
kernels.
add_efi_memmap [EFI; X86] Include EFI memory map in
kernel's map of available physical RAM.

View File

@ -257,6 +257,7 @@ F: Documentation/ABI/testing/sysfs-bus-acpi
F: drivers/pci/*acpi*
F: drivers/pci/*/*acpi*
F: drivers/pci/*/*/*acpi*
F: tools/power/acpi
ACPI COMPONENT ARCHITECTURE (ACPICA)
M: Robert Moore <robert.moore@intel.com>
@ -271,6 +272,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
S: Supported
F: drivers/acpi/acpica/
F: include/acpi/
F: tools/power/acpi/
ACPI FAN DRIVER
M: Zhang Rui <rui.zhang@intel.com>

View File

@ -303,6 +303,11 @@ void __init exynos_cpuidle_init(void)
platform_device_register(&exynos_cpuidle);
}
void __init exynos_cpufreq_init(void)
{
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
}
void __init exynos_init_late(void)
{
if (of_machine_is_compatible("samsung,exynos5440"))

View File

@ -22,6 +22,7 @@ void exynos_init_io(void);
void exynos4_restart(enum reboot_mode mode, const char *cmd);
void exynos5_restart(enum reboot_mode mode, const char *cmd);
void exynos_cpuidle_init(void);
void exynos_cpufreq_init(void);
void exynos_init_late(void);
void exynos_firmware_init(void);

View File

@ -172,8 +172,8 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev,
{
int new_index = index;
/* This mode only can be entered when other core's are offline */
if (num_online_cpus() > 1)
/* AFTR can only be entered when cores other than CPU0 are offline */
if (num_online_cpus() > 1 || dev->cpu != 0)
new_index = drv->safe_state_index;
if (new_index == 0)
@ -235,10 +235,6 @@ static int exynos_cpuidle_probe(struct platform_device *pdev)
device = &per_cpu(exynos4_cpuidle_device, cpu_id);
device->cpu = cpu_id;
/* Support IDLE only */
if (cpu_id != 0)
device->state_count = 1;
ret = cpuidle_register_device(device);
if (ret) {
dev_err(&pdev->dev, "failed to register cpuidle device\n");

View File

@ -22,6 +22,7 @@
static void __init exynos4_dt_machine_init(void)
{
exynos_cpuidle_init();
exynos_cpufreq_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}

View File

@ -44,6 +44,7 @@ static void __init exynos5_dt_machine_init(void)
}
exynos_cpuidle_init();
exynos_cpufreq_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}

View File

@ -33,6 +33,13 @@ struct clk clk_##_name = { \
static DEFINE_SPINLOCK(clocks_lock);
/* Dummy clk routine to build generic kernel parts that may be using them */
unsigned long clk_get_rate(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_get_rate);
static void clk_gpio27_enable(struct clk *clk)
{
/*

View File

@ -23,8 +23,7 @@
*/
#include <linux/module.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <asm/sal.h>
MODULE_AUTHOR("Bjorn Helgaas <bjorn.helgaas@hp.com>");

View File

@ -60,7 +60,6 @@
#define PREFIX "ACPI: "
u32 acpi_rsdt_forced;
unsigned int acpi_cpei_override;
unsigned int acpi_cpei_phys_cpuid;

View File

@ -28,7 +28,6 @@ struct cpuidle_driver pseries_idle_driver = {
#define MAX_IDLE_STATE_COUNT 2
static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
static struct cpuidle_device __percpu *pseries_cpuidle_devices;
static struct cpuidle_state *cpuidle_state_table;
static inline void idle_loop_prolog(unsigned long *in_purr)
@ -191,7 +190,7 @@ static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
{
int hotcpu = (unsigned long)hcpu;
struct cpuidle_device *dev =
per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
per_cpu_ptr(cpuidle_devices, hotcpu);
if (dev && cpuidle_get_driver()) {
switch (action) {
@ -248,50 +247,6 @@ static int pseries_cpuidle_driver_init(void)
return 0;
}
/* pseries_idle_devices_uninit(void)
* unregister cpuidle devices and de-allocate memory
*/
static void pseries_idle_devices_uninit(void)
{
int i;
struct cpuidle_device *dev;
for_each_possible_cpu(i) {
dev = per_cpu_ptr(pseries_cpuidle_devices, i);
cpuidle_unregister_device(dev);
}
free_percpu(pseries_cpuidle_devices);
return;
}
/* pseries_idle_devices_init()
* allocate, initialize and register cpuidle device
*/
static int pseries_idle_devices_init(void)
{
int i;
struct cpuidle_driver *drv = &pseries_idle_driver;
struct cpuidle_device *dev;
pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
if (pseries_cpuidle_devices == NULL)
return -ENOMEM;
for_each_possible_cpu(i) {
dev = per_cpu_ptr(pseries_cpuidle_devices, i);
dev->state_count = drv->state_count;
dev->cpu = i;
if (cpuidle_register_device(dev)) {
printk(KERN_DEBUG \
"cpuidle_register_device %d failed!\n", i);
return -EIO;
}
}
return 0;
}
/*
* pseries_idle_probe()
* Choose state table for shared versus dedicated partition
@ -327,19 +282,12 @@ static int __init pseries_processor_idle_init(void)
return retval;
pseries_cpuidle_driver_init();
retval = cpuidle_register_driver(&pseries_idle_driver);
retval = cpuidle_register(&pseries_idle_driver, NULL);
if (retval) {
printk(KERN_DEBUG "Registration of pseries driver failed.\n");
return retval;
}
retval = pseries_idle_devices_init();
if (retval) {
pseries_idle_devices_uninit();
cpuidle_unregister_driver(&pseries_idle_driver);
return retval;
}
register_cpu_notifier(&setup_hotplug_notifier);
printk(KERN_DEBUG "pseries_idle_driver registered\n");
@ -350,8 +298,7 @@ static void __exit pseries_processor_idle_exit(void)
{
unregister_cpu_notifier(&setup_hotplug_notifier);
pseries_idle_devices_uninit();
cpuidle_unregister_driver(&pseries_idle_driver);
cpuidle_unregister(&pseries_idle_driver);
return;
}

View File

@ -46,7 +46,6 @@
#include "sleep.h" /* To include x86_acpi_suspend_lowlevel */
static int __initdata acpi_force = 0;
u32 acpi_rsdt_forced;
int acpi_disabled;
EXPORT_SYMBOL(acpi_disabled);
@ -1562,7 +1561,7 @@ static int __init parse_acpi(char *arg)
}
/* acpi=rsdt use RSDT instead of XSDT */
else if (strcmp(arg, "rsdt") == 0) {
acpi_rsdt_forced = 1;
acpi_gbl_do_not_use_xsdt = TRUE;
}
/* "acpi=noirq" disables ACPI interrupt routing */
else if (strcmp(arg, "noirq") == 0) {

View File

@ -20,9 +20,7 @@
#include <asm/apic.h>
#include <asm/ipi.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
#include <linux/acpi.h>
static struct apic apic_physflat;
static struct apic apic_flat;

View File

@ -37,9 +37,6 @@
#include <linux/kthread.h>
#include <linux/jiffies.h> /* time_after() */
#include <linux/slab.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
#include <linux/bootmem.h>
#include <linux/dmar.h>
#include <linux/hpet.h>

View File

@ -12,7 +12,6 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/sfi_acpi.h>
#include <linux/bitmap.h>
#include <linux/dmi.h>

View File

@ -14,7 +14,6 @@
#include <linux/rcupdate.h>
#include <asm/e820.h>
#include <asm/pci_x86.h>
#include <acpi/acpi.h>
/* Assume systems with more busses have correct MCFG */
#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))

View File

@ -15,8 +15,7 @@
#include <linux/power_supply.h>
#include <linux/olpc-ec.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <asm/olpc.h>
#define DRV_NAME "olpc-xo15-sci"

View File

@ -32,8 +32,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#define PREFIX "ACPI: "

View File

@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <linux/cper.h>
#include <linux/ratelimit.h>
#include <linux/edac.h>
@ -21,11 +20,9 @@
#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */
#define EXTLOG_DSM_REV 0x0
#define EXTLOG_FN_QUERY 0x0
#define EXTLOG_FN_ADDR 0x1
#define FLAG_OS_OPTIN BIT(0)
#define EXTLOG_QUERY_L1_EXIST BIT(1)
#define ELOG_ENTRY_VALID (1ULL<<63)
#define ELOG_ENTRY_LEN 0x1000
@ -46,7 +43,7 @@ struct extlog_l1_head {
static int old_edac_report_status;
static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295";
static u8 extlog_dsm_uuid[] __initdata = "663E35AF-CC10-41A4-88EA-5470AF055295";
/* L1 table related physical address */
static u64 elog_base;
@ -156,62 +153,27 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
return NOTIFY_STOP;
}
static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret)
static bool __init extlog_get_l1addr(void)
{
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_object_list input;
union acpi_object params[4], *obj;
u8 uuid[16];
int i;
acpi_handle handle;
union acpi_object *obj;
acpi_str_to_uuid(extlog_dsm_uuid, uuid);
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = 16;
params[0].buffer.pointer = uuid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = rev;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = func;
params[3].type = ACPI_TYPE_PACKAGE;
params[3].package.count = 0;
params[3].package.elements = NULL;
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf)))
return -1;
*ret = 0;
obj = (union acpi_object *)buf.pointer;
if (obj->type == ACPI_TYPE_INTEGER) {
*ret = obj->integer.value;
} else if (obj->type == ACPI_TYPE_BUFFER) {
if (obj->buffer.length <= 8) {
for (i = 0; i < obj->buffer.length; i++)
*ret |= (obj->buffer.pointer[i] << (i * 8));
}
}
kfree(buf.pointer);
return 0;
}
static bool extlog_get_l1addr(void)
{
acpi_handle handle;
u64 ret;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
return false;
if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) ||
!(ret & EXTLOG_QUERY_L1_EXIST))
if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
return false;
if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret))
obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV,
EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER);
if (!obj) {
return false;
} else {
l1_dirbase = obj->integer.value;
ACPI_FREE(obj);
}
l1_dirbase = ret;
/* Spec says L1 directory must be 4K aligned, bail out if it isn't */
if (l1_dirbase & ((1 << 12) - 1)) {
pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n",

View File

@ -180,14 +180,14 @@ static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info)
static int acpi_bind_memblk(struct memory_block *mem, void *arg)
{
return acpi_bind_one(&mem->dev, (acpi_handle)arg);
return acpi_bind_one(&mem->dev, arg);
}
static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
acpi_handle handle)
struct acpi_device *adev)
{
return walk_memory_range(acpi_meminfo_start_pfn(info),
acpi_meminfo_end_pfn(info), (void *)handle,
acpi_meminfo_end_pfn(info), adev,
acpi_bind_memblk);
}
@ -197,8 +197,7 @@ static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
return 0;
}
static void acpi_unbind_memory_blocks(struct acpi_memory_info *info,
acpi_handle handle)
static void acpi_unbind_memory_blocks(struct acpi_memory_info *info)
{
walk_memory_range(acpi_meminfo_start_pfn(info),
acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk);
@ -242,9 +241,9 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
if (result && result != -EEXIST)
continue;
result = acpi_bind_memory_blocks(info, handle);
result = acpi_bind_memory_blocks(info, mem_device->device);
if (result) {
acpi_unbind_memory_blocks(info, handle);
acpi_unbind_memory_blocks(info);
return -ENODEV;
}
@ -285,7 +284,7 @@ static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
if (nid == NUMA_NO_NODE)
nid = memory_add_physaddr_to_nid(info->start_addr);
acpi_unbind_memory_blocks(info, handle);
acpi_unbind_memory_blocks(info);
remove_memory(nid, info->start_addr, info->length);
list_del(&info->list);
kfree(info);
@ -361,7 +360,19 @@ static void acpi_memory_device_remove(struct acpi_device *device)
acpi_memory_device_free(mem_device);
}
static bool __initdata acpi_no_memhotplug;
void __init acpi_memory_hotplug_init(void)
{
if (acpi_no_memhotplug)
return;
acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
}
static int __init disable_acpi_memory_hotplug(char *str)
{
acpi_no_memhotplug = true;
return 1;
}
__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug);

View File

@ -28,8 +28,7 @@
#include <linux/cpu.h>
#include <linux/clockchips.h>
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <asm/mwait.h>
#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"

View File

@ -212,7 +212,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
struct acpi_processor *pr = acpi_driver_data(device);
int cpu_index, device_declaration = 0;
int apic_id, cpu_index, device_declaration = 0;
acpi_status status = AE_OK;
static int cpu0_initialized;
unsigned long long value;
@ -258,18 +258,21 @@ static int acpi_processor_get_info(struct acpi_device *device)
device_declaration = 1;
pr->acpi_id = value;
}
pr->apic_id = acpi_get_apicid(pr->handle, device_declaration,
pr->acpi_id);
cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
if (!cpu0_initialized && (cpu_index == -1) &&
(num_online_cpus() == 1)) {
cpu_index = 0;
apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
if (apic_id < 0) {
acpi_handle_err(pr->handle, "failed to get CPU APIC ID.\n");
return -ENODEV;
}
pr->apic_id = apic_id;
cpu0_initialized = 1;
cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
if (!cpu0_initialized) {
cpu0_initialized = 1;
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
if ((cpu_index == -1) && (num_online_cpus() == 1))
cpu_index = 0;
}
pr->id = cpu_index;
/*
@ -282,6 +285,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
if (ret)
return ret;
}
/*
* On some boxes several processors use the same processor bus id.
* But they are located in different scope. For example:
@ -395,7 +399,7 @@ static int acpi_processor_add(struct acpi_device *device,
goto err;
}
result = acpi_bind_one(dev, pr->handle);
result = acpi_bind_one(dev, device);
if (result)
goto err;

View File

@ -113,7 +113,6 @@ void acpi_db_display_handlers(void);
ACPI_HW_DEPENDENT_RETURN_VOID(void
acpi_db_generate_gpe(char *gpe_arg,
char *block_arg))
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void))
/*

View File

@ -71,9 +71,8 @@ acpi_status acpi_ev_init_global_lock_handler(void);
ACPI_HW_DEPENDENT_RETURN_OK(acpi_status
acpi_ev_acquire_global_lock(u16 timeout))
ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_release_global_lock(void))
acpi_status acpi_ev_remove_global_lock_handler(void);
acpi_status acpi_ev_remove_global_lock_handler(void);
/*
* evgpe - Low-level GPE support
@ -133,7 +132,7 @@ acpi_status acpi_ev_gpe_initialize(void);
ACPI_HW_DEPENDENT_RETURN_VOID(void
acpi_ev_update_gpes(acpi_owner_id table_owner_id))
acpi_status
acpi_status
acpi_ev_match_gpe_method(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
@ -149,7 +148,9 @@ acpi_status
acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block, void *context);
struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number);
acpi_status
acpi_ev_get_gpe_xrupt_block(u32 interrupt_number,
struct acpi_gpe_xrupt_info **gpe_xrupt_block);
acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt);

View File

@ -118,6 +118,24 @@ bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
/*
* Optionally ignore an XSDT if present and use the RSDT instead.
* Although the ACPI specification requires that an XSDT be used instead
* of the RSDT, the XSDT has been found to be corrupt or ill-formed on
* some machines. Default behavior is to use the XSDT if present.
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
/*
* Optionally use 32-bit FADT addresses if and when there is a conflict
* (address mismatch) between the 32-bit and 64-bit versions of the
* address. Although ACPICA adheres to the ACPI specification which
* requires the use of the corresponding 64-bit address if it is non-zero,
* some machines have been found to have a corrupted non-zero 64-bit
* address. Default is FALSE, do not favor the 32-bit addresses.
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
/*
* Optionally truncate I/O addresses to 16 bits. Provides compatibility
* with other ACPI implementations. NOTE: During ACPICA initialization,
@ -482,6 +500,18 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
#endif /* ACPI_DEBUGGER */
/*****************************************************************************
*
* Application globals
*
****************************************************************************/
#ifdef ACPI_APPLICATION
ACPI_FILE ACPI_INIT_GLOBAL(acpi_gbl_debug_file, NULL);
#endif /* ACPI_APPLICATION */
/*****************************************************************************
*
* Info/help support

View File

@ -1038,15 +1038,16 @@ struct acpi_external_list {
struct acpi_external_list *next;
u32 value;
u16 length;
u16 flags;
u8 type;
u8 flags;
u8 resolved;
u8 emitted;
};
/* Values for Flags field above */
#define ACPI_IPATH_ALLOCATED 0x01
#define ACPI_EXT_RESOLVED_REFERENCE 0x01 /* Object was resolved during cross ref */
#define ACPI_EXT_ORIGIN_FROM_FILE 0x02 /* External came from a file */
#define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */
#define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */
struct acpi_external_file {
char *path;

View File

@ -105,7 +105,7 @@ acpi_ds_create_external_region(acpi_status lookup_status,
* operation_region not found. Generate an External for it, and
* insert the name into the namespace.
*/
acpi_dm_add_to_external_list(op, path, ACPI_TYPE_REGION, 0);
acpi_dm_add_op_to_external_list(op, path, ACPI_TYPE_REGION, 0, 0);
status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION,
ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT,
walk_state, node);

View File

@ -727,27 +727,26 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
index++;
}
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"NumOperands %d, ArgCount %d, Index %d\n",
walk_state->num_operands, arg_count, index));
/* Create the interpreter arguments, in reverse order */
index--;
/* It is the appropriate order to get objects from the Result stack */
for (i = 0; i < arg_count; i++) {
arg = arguments[index];
/* Force the filling of the operand stack in inverse order */
walk_state->operand_index = (u8) index;
walk_state->operand_index = (u8)index;
status = acpi_ds_create_operand(walk_state, arg, index);
if (ACPI_FAILURE(status)) {
goto cleanup;
}
index--;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Arg #%u (%p) done, Arg1=%p\n", index, arg,
first_arg));
"Created Arg #%u (%p) %u args total\n",
index, arg, arg_count));
index--;
}
return_ACPI_STATUS(status);

View File

@ -181,8 +181,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* Target of Scope() not found. Generate an External for it, and
* insert the name into the namespace.
*/
acpi_dm_add_to_external_list(op, path, ACPI_TYPE_DEVICE,
0);
acpi_dm_add_op_to_external_list(op, path,
ACPI_TYPE_DEVICE, 0, 0);
status =
acpi_ns_lookup(walk_state->scope_info, path,
object_type, ACPI_IMODE_LOAD_PASS1,

View File

@ -87,9 +87,9 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
return_ACPI_STATUS(status);
}
gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block(interrupt_number);
if (!gpe_xrupt_block) {
status = AE_NO_MEMORY;
status =
acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@ -112,7 +112,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
unlock_and_exit:
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}

View File

@ -197,8 +197,9 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
* FUNCTION: acpi_ev_get_gpe_xrupt_block
*
* PARAMETERS: interrupt_number - Interrupt for a GPE block
* gpe_xrupt_block - Where the block is returned
*
* RETURN: A GPE interrupt block
* RETURN: Status
*
* DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
* block per unique interrupt level used for GPEs. Should be
@ -207,7 +208,9 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
*
******************************************************************************/
struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number)
acpi_status
acpi_ev_get_gpe_xrupt_block(u32 interrupt_number,
struct acpi_gpe_xrupt_info ** gpe_xrupt_block)
{
struct acpi_gpe_xrupt_info *next_gpe_xrupt;
struct acpi_gpe_xrupt_info *gpe_xrupt;
@ -221,7 +224,8 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number)
next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
while (next_gpe_xrupt) {
if (next_gpe_xrupt->interrupt_number == interrupt_number) {
return_PTR(next_gpe_xrupt);
*gpe_xrupt_block = next_gpe_xrupt;
return_ACPI_STATUS(AE_OK);
}
next_gpe_xrupt = next_gpe_xrupt->next;
@ -231,7 +235,7 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number)
gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));
if (!gpe_xrupt) {
return_PTR(NULL);
return_ACPI_STATUS(AE_NO_MEMORY);
}
gpe_xrupt->interrupt_number = interrupt_number;
@ -250,6 +254,7 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number)
} else {
acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;
}
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
/* Install new interrupt handler if not SCI_INT */
@ -259,14 +264,15 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number)
acpi_ev_gpe_xrupt_handler,
gpe_xrupt);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO,
"Could not install GPE interrupt handler at level 0x%X",
interrupt_number));
return_PTR(NULL);
ACPI_EXCEPTION((AE_INFO, status,
"Could not install GPE interrupt handler at level 0x%X",
interrupt_number));
return_ACPI_STATUS(status);
}
}
return_PTR(gpe_xrupt);
*gpe_xrupt_block = gpe_xrupt;
return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************

View File

@ -124,7 +124,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
}
if (!source_desc) {
ACPI_ERROR((AE_INFO, "No object attached to node %p", node));
ACPI_ERROR((AE_INFO, "No object attached to node [%4.4s] %p",
node->name.ascii, node));
return_ACPI_STATUS(AE_AML_NO_OPERAND);
}

View File

@ -84,7 +84,7 @@ acpi_evaluate_object_typed(acpi_handle handle,
acpi_object_type return_type)
{
acpi_status status;
u8 must_free = FALSE;
u8 free_buffer_on_error = FALSE;
ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed);
@ -95,14 +95,13 @@ acpi_evaluate_object_typed(acpi_handle handle,
}
if (return_buffer->length == ACPI_ALLOCATE_BUFFER) {
must_free = TRUE;
free_buffer_on_error = TRUE;
}
/* Evaluate the object */
status =
acpi_evaluate_object(handle, pathname, external_params,
return_buffer);
status = acpi_evaluate_object(handle, pathname,
external_params, return_buffer);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@ -135,11 +134,15 @@ acpi_evaluate_object_typed(acpi_handle handle,
pointer)->type),
acpi_ut_get_type_name(return_type)));
if (must_free) {
/* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */
ACPI_FREE_BUFFER(*return_buffer);
if (free_buffer_on_error) {
/*
* Free a buffer created via ACPI_ALLOCATE_BUFFER.
* Note: We use acpi_os_free here because acpi_os_allocate was used
* to allocate the buffer. This purposefully bypasses the
* (optionally enabled) allocation tracking mechanism since we
* only want to track internal allocations.
*/
acpi_os_free(return_buffer->pointer);
return_buffer->pointer = NULL;
}

View File

@ -71,6 +71,10 @@ static const u8 acpi_gbl_argument_count[] =
const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
{
#ifdef ACPI_DEBUG_OUTPUT
const char *opcode_name = "Unknown AML opcode";
#endif
ACPI_FUNCTION_NAME(ps_get_opcode_info);
/*
@ -92,11 +96,54 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
return (&acpi_gbl_aml_op_info
[acpi_gbl_long_op_index[(u8)opcode]]);
}
#if defined ACPI_ASL_COMPILER && defined ACPI_DEBUG_OUTPUT
#include "asldefine.h"
switch (opcode) {
case AML_RAW_DATA_BYTE:
opcode_name = "-Raw Data Byte-";
break;
case AML_RAW_DATA_WORD:
opcode_name = "-Raw Data Word-";
break;
case AML_RAW_DATA_DWORD:
opcode_name = "-Raw Data Dword-";
break;
case AML_RAW_DATA_QWORD:
opcode_name = "-Raw Data Qword-";
break;
case AML_RAW_DATA_BUFFER:
opcode_name = "-Raw Data Buffer-";
break;
case AML_RAW_DATA_CHAIN:
opcode_name = "-Raw Data Buffer Chain-";
break;
case AML_PACKAGE_LENGTH:
opcode_name = "-Package Length-";
break;
case AML_UNASSIGNED_OPCODE:
opcode_name = "-Unassigned Opcode-";
break;
case AML_DEFAULT_ARG_OP:
opcode_name = "-Default Arg-";
break;
default:
break;
}
#endif
/* Unknown AML opcode */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Unknown AML opcode [%4.4X]\n", opcode));
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%4.4X]\n", opcode_name, opcode));
return (&acpi_gbl_aml_op_info[_UNK]);
}

View File

@ -56,10 +56,11 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
static void acpi_tb_convert_fadt(void);
static void acpi_tb_validate_fadt(void);
static void acpi_tb_setup_fadt_registers(void);
static u64
acpi_tb_select_address(char *register_name, u32 address32, u64 address64);
/* Table for conversion of FADT to common internal format and FADT validation */
typedef struct acpi_fadt_info {
@ -175,6 +176,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
* space_id - ACPI Space ID for this register
* byte_width - Width of this register
* address - Address of the register
* register_name - ASCII name of the ACPI register
*
* RETURN: None
*
@ -218,6 +220,68 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
generic_address->access_width = 0; /* Access width ANY */
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_select_address
*
* PARAMETERS: register_name - ASCII name of the ACPI register
* address32 - 32-bit address of the register
* address64 - 64-bit address of the register
*
* RETURN: The resolved 64-bit address
*
* DESCRIPTION: Select between 32-bit and 64-bit versions of addresses within
* the FADT. Used for the FACS and DSDT addresses.
*
* NOTES:
*
* Check for FACS and DSDT address mismatches. An address mismatch between
* the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and
* DSDT/X_DSDT) could be a corrupted address field or it might indicate
* the presence of two FACS or two DSDT tables.
*
* November 2013:
* By default, as per the ACPICA specification, a valid 64-bit address is
* used regardless of the value of the 32-bit address. However, this
* behavior can be overridden via the acpi_gbl_use32_bit_fadt_addresses flag.
*
******************************************************************************/
static u64
acpi_tb_select_address(char *register_name, u32 address32, u64 address64)
{
if (!address64) {
/* 64-bit address is zero, use 32-bit address */
return ((u64)address32);
}
if (address32 && (address64 != (u64)address32)) {
/* Address mismatch between 32-bit and 64-bit versions */
ACPI_BIOS_WARNING((AE_INFO,
"32/64X %s address mismatch in FADT: "
"0x%8.8X/0x%8.8X%8.8X, using %u-bit address",
register_name, address32,
ACPI_FORMAT_UINT64(address64),
acpi_gbl_use32_bit_fadt_addresses ? 32 :
64));
/* 32-bit address override */
if (acpi_gbl_use32_bit_fadt_addresses) {
return ((u64)address32);
}
}
/* Default is to use the 64-bit address */
return (address64);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_parse_fadt
@ -331,10 +395,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
acpi_tb_convert_fadt();
/* Validate FADT values now, before we make any changes */
acpi_tb_validate_fadt();
/* Initialize the global ACPI register structures */
acpi_tb_setup_fadt_registers();
@ -344,65 +404,54 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
*
* FUNCTION: acpi_tb_convert_fadt
*
* PARAMETERS: None, uses acpi_gbl_FADT
* PARAMETERS: none - acpi_gbl_FADT is used.
*
* RETURN: None
*
* DESCRIPTION: Converts all versions of the FADT to a common internal format.
* Expand 32-bit addresses to 64-bit as necessary.
* Expand 32-bit addresses to 64-bit as necessary. Also validate
* important fields within the FADT.
*
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
* and must contain a copy of the actual FADT.
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), and must
* contain a copy of the actual BIOS-provided FADT.
*
* Notes on 64-bit register addresses:
*
* After this FADT conversion, later ACPICA code will only use the 64-bit "X"
* fields of the FADT for all ACPI register addresses.
*
* The 64-bit "X" fields are optional extensions to the original 32-bit FADT
* The 64-bit X fields are optional extensions to the original 32-bit FADT
* V1.0 fields. Even if they are present in the FADT, they are optional and
* are unused if the BIOS sets them to zero. Therefore, we must copy/expand
* 32-bit V1.0 fields if the corresponding X field is zero.
* 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is
* originally zero.
*
* For ACPI 1.0 FADTs, all 32-bit address fields are expanded to the
* corresponding "X" fields in the internal FADT.
* For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address
* fields are expanded to the corresponding 64-bit X fields in the internal
* common FADT.
*
* For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded
* to the corresponding 64-bit X fields. For compatibility with other ACPI
* implementations, we ignore the 64-bit field if the 32-bit field is valid,
* regardless of whether the host OS is 32-bit or 64-bit.
* to the corresponding 64-bit X fields, if the 64-bit field is originally
* zero. Adhering to the ACPI specification, we completely ignore the 32-bit
* field if the 64-bit field is valid, regardless of whether the host OS is
* 32-bit or 64-bit.
*
* Possible additional checks:
* (acpi_gbl_FADT.pm1_event_length >= 4)
* (acpi_gbl_FADT.pm1_control_length >= 2)
* (acpi_gbl_FADT.pm_timer_length >= 4)
* Gpe block lengths must be multiple of 2
*
******************************************************************************/
static void acpi_tb_convert_fadt(void)
{
char *name;
struct acpi_generic_address *address64;
u32 address32;
u8 length;
u32 i;
/*
* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary.
* Later code will always use the X 64-bit field. Also, check for an
* address mismatch between the 32-bit and 64-bit address fields
* (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate
* the presence of two FACS or two DSDT tables.
*/
if (!acpi_gbl_FADT.Xfacs) {
acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
} else if (acpi_gbl_FADT.facs &&
(acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) {
ACPI_WARNING((AE_INFO,
"32/64 FACS address mismatch in FADT - two FACS tables!"));
}
if (!acpi_gbl_FADT.Xdsdt) {
acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
} else if (acpi_gbl_FADT.dsdt &&
(acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) {
ACPI_WARNING((AE_INFO,
"32/64 DSDT address mismatch in FADT - two DSDT tables!"));
}
/*
* For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
* should be zero are indeed zero. This will workaround BIOSs that
@ -421,119 +470,24 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_FADT.boot_flags = 0;
}
/* Update the local FADT table header length */
/*
* Now we can update the local FADT length to the length of the
* current FADT version as defined by the ACPI specification.
* Thus, we will have a common FADT internally.
*/
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
/*
* Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
* generic address structures as necessary. Later code will always use
* the 64-bit address structures.
*
* March 2009:
* We now always use the 32-bit address if it is valid (non-null). This
* is not in accordance with the ACPI specification which states that
* the 64-bit address supersedes the 32-bit version, but we do this for
* compatibility with other ACPI implementations. Most notably, in the
* case where both the 32 and 64 versions are non-null, we use the 32-bit
* version. This is the only address that is guaranteed to have been
* tested by the BIOS manufacturer.
* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary.
* Later ACPICA code will always use the X 64-bit field.
*/
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
address32 = *ACPI_ADD_PTR(u32,
&acpi_gbl_FADT,
fadt_info_table[i].address32);
acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS",
acpi_gbl_FADT.facs,
acpi_gbl_FADT.Xfacs);
address64 = ACPI_ADD_PTR(struct acpi_generic_address,
&acpi_gbl_FADT,
fadt_info_table[i].address64);
/*
* If both 32- and 64-bit addresses are valid (non-zero),
* they must match.
*/
if (address64->address && address32 &&
(address64->address != (u64)address32)) {
ACPI_BIOS_ERROR((AE_INFO,
"32/64X address mismatch in FADT/%s: "
"0x%8.8X/0x%8.8X%8.8X, using 32",
fadt_info_table[i].name, address32,
ACPI_FORMAT_UINT64(address64->
address)));
}
/* Always use 32-bit address if it is valid (non-null) */
if (address32) {
/*
* Copy the 32-bit address to the 64-bit GAS structure. The
* Space ID is always I/O for 32-bit legacy address fields
*/
acpi_tb_init_generic_address(address64,
ACPI_ADR_SPACE_SYSTEM_IO,
*ACPI_ADD_PTR(u8,
&acpi_gbl_FADT,
fadt_info_table
[i].length),
(u64) address32,
fadt_info_table[i].name);
}
}
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_fadt
*
* PARAMETERS: table - Pointer to the FADT to be validated
*
* RETURN: None
*
* DESCRIPTION: Validate various important fields within the FADT. If a problem
* is found, issue a message, but no status is returned.
* Used by both the table manager and the disassembler.
*
* Possible additional checks:
* (acpi_gbl_FADT.pm1_event_length >= 4)
* (acpi_gbl_FADT.pm1_control_length >= 2)
* (acpi_gbl_FADT.pm_timer_length >= 4)
* Gpe block lengths must be multiple of 2
*
******************************************************************************/
static void acpi_tb_validate_fadt(void)
{
char *name;
struct acpi_generic_address *address64;
u8 length;
u32 i;
/*
* Check for FACS and DSDT address mismatches. An address mismatch between
* the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and
* DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables.
*/
if (acpi_gbl_FADT.facs &&
(acpi_gbl_FADT.Xfacs != (u64)acpi_gbl_FADT.facs)) {
ACPI_BIOS_WARNING((AE_INFO,
"32/64X FACS address mismatch in FADT - "
"0x%8.8X/0x%8.8X%8.8X, using 32",
acpi_gbl_FADT.facs,
ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs)));
acpi_gbl_FADT.Xfacs = (u64)acpi_gbl_FADT.facs;
}
if (acpi_gbl_FADT.dsdt &&
(acpi_gbl_FADT.Xdsdt != (u64)acpi_gbl_FADT.dsdt)) {
ACPI_BIOS_WARNING((AE_INFO,
"32/64X DSDT address mismatch in FADT - "
"0x%8.8X/0x%8.8X%8.8X, using 32",
acpi_gbl_FADT.dsdt,
ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt)));
acpi_gbl_FADT.Xdsdt = (u64)acpi_gbl_FADT.dsdt;
}
acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT",
acpi_gbl_FADT.dsdt,
acpi_gbl_FADT.Xdsdt);
/* If Hardware Reduced flag is set, we are all done */
@ -545,17 +499,94 @@ static void acpi_tb_validate_fadt(void)
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
/*
* Generate pointer to the 64-bit address, get the register
* length (width) and the register name
* Get the 32-bit and 64-bit addresses, as well as the register
* length and register name.
*/
address32 = *ACPI_ADD_PTR(u32,
&acpi_gbl_FADT,
fadt_info_table[i].address32);
address64 = ACPI_ADD_PTR(struct acpi_generic_address,
&acpi_gbl_FADT,
fadt_info_table[i].address64);
length =
*ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
fadt_info_table[i].length);
length = *ACPI_ADD_PTR(u8,
&acpi_gbl_FADT,
fadt_info_table[i].length);
name = fadt_info_table[i].name;
/*
* Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
* generic address structures as necessary. Later code will always use
* the 64-bit address structures.
*
* November 2013:
* Now always use the 64-bit address if it is valid (non-zero), in
* accordance with the ACPI specification which states that a 64-bit
* address supersedes the 32-bit version. This behavior can be
* overridden by the acpi_gbl_use32_bit_fadt_addresses flag.
*
* During 64-bit address construction and verification,
* these cases are handled:
*
* Address32 zero, Address64 [don't care] - Use Address64
*
* Address32 non-zero, Address64 zero - Copy/use Address32
* Address32 non-zero == Address64 non-zero - Use Address64
* Address32 non-zero != Address64 non-zero - Warning, use Address64
*
* Override: if acpi_gbl_use32_bit_fadt_addresses is TRUE, and:
* Address32 non-zero != Address64 non-zero - Warning, copy/use Address32
*
* Note: space_id is always I/O for 32-bit legacy address fields
*/
if (address32) {
if (!address64->address) {
/* 64-bit address is zero, use 32-bit address */
acpi_tb_init_generic_address(address64,
ACPI_ADR_SPACE_SYSTEM_IO,
*ACPI_ADD_PTR(u8,
&acpi_gbl_FADT,
fadt_info_table
[i].
length),
(u64)address32,
name);
} else if (address64->address != (u64)address32) {
/* Address mismatch */
ACPI_BIOS_WARNING((AE_INFO,
"32/64X address mismatch in FADT/%s: "
"0x%8.8X/0x%8.8X%8.8X, using %u-bit address",
name, address32,
ACPI_FORMAT_UINT64
(address64->address),
acpi_gbl_use32_bit_fadt_addresses
? 32 : 64));
if (acpi_gbl_use32_bit_fadt_addresses) {
/* 32-bit address override */
acpi_tb_init_generic_address(address64,
ACPI_ADR_SPACE_SYSTEM_IO,
*ACPI_ADD_PTR
(u8,
&acpi_gbl_FADT,
fadt_info_table
[i].
length),
(u64)
address32,
name);
}
}
}
/*
* For each extended field, check for length mismatch between the
* legacy length field and the corresponding 64-bit X length field.

View File

@ -49,69 +49,11 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address);
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
/*******************************************************************************
*
* FUNCTION: acpi_tb_check_xsdt
*
* PARAMETERS: address - Pointer to the XSDT
*
* RETURN: status
* AE_OK - XSDT is okay
* AE_NO_MEMORY - can't map XSDT
* AE_INVALID_TABLE_LENGTH - invalid table length
* AE_NULL_ENTRY - XSDT has NULL entry
*
* DESCRIPTION: validate XSDT
******************************************************************************/
static acpi_status
acpi_tb_check_xsdt(acpi_physical_address address)
{
struct acpi_table_header *table;
u32 length;
u64 xsdt_entry_address;
u8 *table_entry;
u32 table_count;
int i;
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
if (!table)
return AE_NO_MEMORY;
length = table->length;
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
if (length < sizeof(struct acpi_table_header))
return AE_INVALID_TABLE_LENGTH;
table = acpi_os_map_memory(address, length);
if (!table)
return AE_NO_MEMORY;
/* Calculate the number of tables described in XSDT */
table_count =
(u32) ((table->length -
sizeof(struct acpi_table_header)) / sizeof(u64));
table_entry =
ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
for (i = 0; i < table_count; i++) {
ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
if (!xsdt_entry_address) {
/* XSDT has NULL entry */
break;
}
table_entry += sizeof(u64);
}
acpi_os_unmap_memory(table, length);
if (i < table_count)
return AE_NULL_ENTRY;
else
return AE_OK;
}
#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
@ -383,7 +325,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
* Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
* Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
*/
if (table_entry_size == sizeof(u32)) {
if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
/*
* 32-bit platform, RSDT: Return 32-bit table entry
* 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
@ -413,6 +355,87 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
}
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_xsdt
*
* PARAMETERS: address - Physical address of the XSDT (from RSDP)
*
* RETURN: Status. AE_OK if the table appears to be valid.
*
* DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does
* not contain any NULL entries. A problem that is seen in the
* field is that the XSDT exists, but is actually useless because
* of one or more (or all) NULL entries.
*
******************************************************************************/
static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address)
{
struct acpi_table_header *table;
u8 *next_entry;
acpi_physical_address address;
u32 length;
u32 entry_count;
acpi_status status;
u32 i;
/* Get the XSDT length */
table =
acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header));
if (!table) {
return (AE_NO_MEMORY);
}
length = table->length;
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
/*
* Minimum XSDT length is the size of the standard ACPI header
* plus one physical address entry
*/
if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) {
return (AE_INVALID_TABLE_LENGTH);
}
/* Map the entire XSDT */
table = acpi_os_map_memory(xsdt_address, length);
if (!table) {
return (AE_NO_MEMORY);
}
/* Get the number of entries and pointer to first entry */
status = AE_OK;
next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
ACPI_XSDT_ENTRY_SIZE);
/* Validate each entry (physical address) within the XSDT */
for (i = 0; i < entry_count; i++) {
address =
acpi_tb_get_root_table_entry(next_entry,
ACPI_XSDT_ENTRY_SIZE);
if (!address) {
/* Detected a NULL entry, XSDT is invalid */
status = AE_NULL_ENTRY;
break;
}
next_entry += ACPI_XSDT_ENTRY_SIZE;
}
/* Unmap table */
acpi_os_unmap_memory(table, length);
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_parse_root_table
@ -438,16 +461,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
acpi_physical_address uninitialized_var(rsdt_address);
u32 length;
u8 *table_entry;
acpi_status status;
ACPI_FUNCTION_TRACE(tb_parse_root_table);
/*
* Map the entire RSDP and extract the address of the RSDT or XSDT
*/
/* Map the entire RSDP and extract the address of the RSDT or XSDT */
rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
if (!rsdp) {
return_ACPI_STATUS(AE_NO_MEMORY);
@ -457,24 +478,22 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
ACPI_CAST_PTR(struct acpi_table_header,
rsdp));
/* Differentiate between RSDT and XSDT root tables */
/* Use XSDT if present and not overridden. Otherwise, use RSDT */
if (rsdp->revision > 1 && rsdp->xsdt_physical_address
&& !acpi_rsdt_forced) {
if ((rsdp->revision > 1) &&
rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) {
/*
* Root table is an XSDT (64-bit physical addresses). We must use the
* XSDT if the revision is > 1 and the XSDT pointer is present, as per
* the ACPI specification.
* RSDP contains an XSDT (64-bit physical addresses). We must use
* the XSDT if the revision is > 1 and the XSDT pointer is present,
* as per the ACPI specification.
*/
address = (acpi_physical_address) rsdp->xsdt_physical_address;
table_entry_size = sizeof(u64);
rsdt_address = (acpi_physical_address)
rsdp->rsdt_physical_address;
table_entry_size = ACPI_XSDT_ENTRY_SIZE;
} else {
/* Root table is an RSDT (32-bit physical addresses) */
address = (acpi_physical_address) rsdp->rsdt_physical_address;
table_entry_size = sizeof(u32);
table_entry_size = ACPI_RSDT_ENTRY_SIZE;
}
/*
@ -483,15 +502,25 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
*/
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
if (table_entry_size == sizeof(u64)) {
if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) {
/* XSDT has NULL entry, RSDT is used */
address = rsdt_address;
table_entry_size = sizeof(u32);
ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, "
"using RSDT"));
/*
* If it is present and used, validate the XSDT for access/size
* and ensure that all table entries are at least non-NULL
*/
if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) {
status = acpi_tb_validate_xsdt(address);
if (ACPI_FAILURE(status)) {
ACPI_BIOS_WARNING((AE_INFO,
"XSDT is invalid (%s), using RSDT",
acpi_format_exception(status)));
/* Fall back to the RSDT */
address =
(acpi_physical_address) rsdp->rsdt_physical_address;
table_entry_size = ACPI_RSDT_ENTRY_SIZE;
}
}
/* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
@ -501,12 +530,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
acpi_tb_print_table_header(address, table);
/* Get the length of the full table, verify length and map entire table */
/*
* Validate length of the table, and map entire table.
* Minimum length table must contain at least one entry.
*/
length = table->length;
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
if (length < sizeof(struct acpi_table_header)) {
if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
ACPI_BIOS_ERROR((AE_INFO,
"Invalid table length 0x%X in RSDT/XSDT",
length));
@ -526,22 +557,21 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
return_ACPI_STATUS(status);
}
/* Calculate the number of tables described in the root table */
/* Get the number of entries and pointer to first entry */
table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
table_entry_size);
table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
/*
* First two entries in the table array are reserved for the DSDT
* and FACS, which are not actually present in the RSDT/XSDT - they
* come from the FADT
*/
table_entry =
ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
acpi_gbl_root_table_list.current_table_count = 2;
/*
* Initialize the root table array from the RSDT/XSDT
*/
/* Initialize the root table array from the RSDT/XSDT */
for (i = 0; i < table_count; i++) {
if (acpi_gbl_root_table_list.current_table_count >=
acpi_gbl_root_table_list.max_table_count) {
@ -584,7 +614,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
address, NULL, i);
/* Special case for FADT - get the DSDT and FACS */
/* Special case for FADT - validate it then get the DSDT and FACS */
if (ACPI_COMPARE_NAME
(&acpi_gbl_root_table_list.tables[i].signature,

View File

@ -224,10 +224,11 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
while (range_info) {
/*
* Check if the requested Address/Length overlaps this address_range.
* Four cases to consider:
* Check if the requested address/length overlaps this
* address range. There are four cases to consider:
*
* 1) Input address/length is contained completely in the address range
* 1) Input address/length is contained completely in the
* address range
* 2) Input address/length overlaps range at the range start
* 3) Input address/length overlaps range at the range end
* 4) Input address/length completely encompasses the range
@ -244,11 +245,17 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
region_node);
ACPI_WARNING((AE_INFO,
"0x%p-0x%p %s conflicts with Region %s %d",
"%s range 0x%p-0x%p conflicts with OpRegion 0x%p-0x%p (%s)",
acpi_ut_get_region_name(space_id),
ACPI_CAST_PTR(void, address),
ACPI_CAST_PTR(void, end_address),
acpi_ut_get_region_name(space_id),
pathname, overlap_count));
ACPI_CAST_PTR(void,
range_info->
start_address),
ACPI_CAST_PTR(void,
range_info->
end_address),
pathname));
ACPI_FREE(pathname);
}
}

View File

@ -302,9 +302,13 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
return (AE_BUFFER_OVERFLOW);
case ACPI_ALLOCATE_BUFFER:
/* Allocate a new buffer */
/*
* Allocate a new buffer. We directectly call acpi_os_allocate here to
* purposefully bypass the (optionally enabled) internal allocation
* tracking mechanism since we only want to track internal
* allocations. Note: The caller should use acpi_os_free to free this
* buffer created via ACPI_ALLOCATE_BUFFER.
*/
buffer->pointer = acpi_os_allocate(required_length);
break;

View File

@ -248,12 +248,12 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
ACPI_FUNCTION_NAME(os_acquire_object);
if (!cache) {
return (NULL);
return_PTR(NULL);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
if (ACPI_FAILURE(status)) {
return (NULL);
return_PTR(NULL);
}
ACPI_MEM_TRACKING(cache->requests++);
@ -276,7 +276,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
if (ACPI_FAILURE(status)) {
return (NULL);
return_PTR(NULL);
}
/* Clear (zero) the previously used Object */
@ -299,15 +299,15 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
if (ACPI_FAILURE(status)) {
return (NULL);
return_PTR(NULL);
}
object = ACPI_ALLOCATE_ZEROED(cache->object_size);
if (!object) {
return (NULL);
return_PTR(NULL);
}
}
return (object);
return_PTR(object);
}
#endif /* ACPI_USE_LOCAL_CACHE */

View File

@ -194,9 +194,9 @@ acpi_debug_print(u32 requested_debug_level,
*/
acpi_os_printf("%9s-%04ld ", module_name, line_number);
#ifdef ACPI_EXEC_APP
#ifdef ACPI_APPLICATION
/*
* For acpi_exec only, emit the thread ID and nesting level.
* For acpi_exec/iASL only, emit the thread ID and nesting level.
* Note: nesting level is really only useful during a single-thread
* execution. Otherwise, multiple threads will keep resetting the
* level.

View File

@ -388,11 +388,7 @@ acpi_status acpi_ut_init_globals(void)
/* Public globals */
ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
ACPI_EXPORT_SYMBOL(acpi_gpe_count)
ACPI_EXPORT_SYMBOL(acpi_current_gpe_count)

View File

@ -122,8 +122,16 @@ acpi_status __init acpi_initialize_subsystem(void)
/* If configured, initialize the AML debugger */
ACPI_DEBUGGER_EXEC(status = acpi_db_initialize());
return_ACPI_STATUS(status);
#ifdef ACPI_DEBUGGER
status = acpi_db_initialize();
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"During Debugger initialization"));
return_ACPI_STATUS(status);
}
#endif
return_ACPI_STATUS(AE_OK);
}
ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_subsystem)

View File

@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/acpi_io.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/kref.h>

View File

@ -8,7 +8,6 @@
#include <linux/cper.h>
#include <linux/acpi.h>
#include <linux/acpi_io.h>
struct apei_exec_context;

View File

@ -33,7 +33,6 @@
#include <linux/nmi.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <acpi/acpi.h>
#include <asm/unaligned.h>
#include "apei-internal.h"

View File

@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/acpi_io.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/timer.h>

View File

@ -36,8 +36,7 @@
#include <linux/suspend.h>
#include <asm/unaligned.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <linux/power_supply.h>
#define PREFIX "ACPI: "

View File

@ -30,7 +30,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <linux/dmi.h>
#include "internal.h"
@ -323,6 +322,56 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"),
},
},
{
.callback = dmi_disable_osi_win8,
.ident = "HP ProBook 2013 models",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
},
},
{
.callback = dmi_disable_osi_win8,
.ident = "HP EliteBook 2013 models",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
},
},
{
.callback = dmi_disable_osi_win8,
.ident = "HP ZBook 14",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
},
},
{
.callback = dmi_disable_osi_win8,
.ident = "HP ZBook 15",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
},
},
{
.callback = dmi_disable_osi_win8,
.ident = "HP ZBook 17",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
},
},
{
.callback = dmi_disable_osi_win8,
.ident = "HP EliteBook 8780w",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
},
},
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.

View File

@ -37,8 +37,6 @@
#include <asm/mpspec.h>
#endif
#include <linux/pci.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/apei.h>
#include <linux/dmi.h>
#include <linux/suspend.h>
@ -52,9 +50,6 @@ struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s))
#ifdef CONFIG_X86
static int set_copy_dsdt(const struct dmi_system_id *id)
{
@ -115,18 +110,16 @@ int acpi_bus_get_status(struct acpi_device *device)
if (ACPI_FAILURE(status))
return -ENODEV;
STRUCT_TO_INT(device->status) = (int) sta;
acpi_set_device_status(device, sta);
if (device->status.functional && !device->status.present) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
"functional but not present;\n",
device->pnp.bus_id,
(u32) STRUCT_TO_INT(device->status)));
device->pnp.bus_id, (u32)sta));
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
device->pnp.bus_id,
(u32) STRUCT_TO_INT(device->status)));
device->pnp.bus_id, (u32)sta));
return 0;
}
EXPORT_SYMBOL(acpi_bus_get_status);
@ -339,58 +332,6 @@ static void acpi_bus_osc_support(void)
Notification Handling
-------------------------------------------------------------------------- */
static void acpi_bus_check_device(acpi_handle handle)
{
struct acpi_device *device;
acpi_status status;
struct acpi_device_status old_status;
if (acpi_bus_get_device(handle, &device))
return;
if (!device)
return;
old_status = device->status;
/*
* Make sure this device's parent is present before we go about
* messing with the device.
*/
if (device->parent && !device->parent->status.present) {
device->status = device->parent->status;
return;
}
status = acpi_bus_get_status(device);
if (ACPI_FAILURE(status))
return;
if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
return;
/*
* Device Insertion/Removal
*/
if ((device->status.present) && !(old_status.present)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
/* TBD: Handle device insertion */
} else if (!(device->status.present) && (old_status.present)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
/* TBD: Handle device removal */
}
}
static void acpi_bus_check_scope(acpi_handle handle)
{
/* Status Change? */
acpi_bus_check_device(handle);
/*
* TBD: Enumerate child devices within this device's scope and
* run acpi_bus_check_device()'s on them.
*/
}
/**
* acpi_bus_notify
* ---------------
@ -407,19 +348,11 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_bus_check_scope(handle);
/*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
*/
/* TBD */
break;
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_bus_check_device(handle);
/*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
*/
/* TBD */
break;
case ACPI_NOTIFY_DEVICE_WAKE:

View File

@ -31,8 +31,7 @@
#include <linux/seq_file.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <acpi/button.h>
#define PREFIX "ACPI: "
@ -101,7 +100,6 @@ struct acpi_button {
struct input_dev *input;
char phys[32]; /* for input device */
unsigned long pushed;
bool wakeup_enabled;
};
static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
@ -407,16 +405,6 @@ static int acpi_button_add(struct acpi_device *device)
lid_device = device;
}
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
acpi_enable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
if (!device_may_wakeup(&device->dev)) {
device_set_wakeup_enable(&device->dev, true);
button->wakeup_enabled = true;
}
}
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
return 0;
@ -433,13 +421,6 @@ static int acpi_button_remove(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
if (device->wakeup.flags.valid) {
acpi_disable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
if (button->wakeup_enabled)
device_set_wakeup_enable(&device->dev, false);
}
acpi_button_remove_fs(device);
input_unregister_device(button->input);
kfree(button);

View File

@ -27,8 +27,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/acpi.h>
#include "internal.h"
#include <linux/container.h>
#include "internal.h"
@ -44,19 +43,65 @@ static const struct acpi_device_id container_device_ids[] = {
{"", 0},
};
static int container_device_attach(struct acpi_device *device,
static int acpi_container_offline(struct container_dev *cdev)
{
struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
struct acpi_device *child;
/* Check all of the dependent devices' physical companions. */
list_for_each_entry(child, &adev->children, node)
if (!acpi_scan_is_offline(child, false))
return -EBUSY;
return 0;
}
static void acpi_container_release(struct device *dev)
{
kfree(to_container_dev(dev));
}
static int container_device_attach(struct acpi_device *adev,
const struct acpi_device_id *not_used)
{
/* This is necessary for container hotplug to work. */
struct container_dev *cdev;
struct device *dev;
int ret;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
cdev->offline = acpi_container_offline;
dev = &cdev->dev;
dev->bus = &container_subsys;
dev_set_name(dev, "%s", dev_name(&adev->dev));
ACPI_COMPANION_SET(dev, adev);
dev->release = acpi_container_release;
ret = device_register(dev);
if (ret)
return ret;
adev->driver_data = dev;
return 1;
}
static void container_device_detach(struct acpi_device *adev)
{
struct device *dev = acpi_driver_data(adev);
adev->driver_data = NULL;
if (dev)
device_unregister(dev);
}
static struct acpi_scan_handler container_handler = {
.ids = container_device_ids,
.attach = container_device_attach,
.detach = container_device_detach,
.hotplug = {
.enabled = true,
.mode = AHM_CONTAINER,
.demand_offline = true,
},
};

View File

@ -7,7 +7,7 @@
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include "internal.h"

View File

@ -5,7 +5,7 @@
#include <linux/export.h>
#include <linux/init.h>
#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("debugfs");

View File

@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device)
return -EINVAL;
device->power.state = ACPI_STATE_UNKNOWN;
if (!acpi_device_is_present(device))
return 0;
result = acpi_device_get_power(device, &state);
if (result)
@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device)
return ret;
}
int acpi_bus_update_power(acpi_handle handle, int *state_p)
int acpi_device_update_power(struct acpi_device *device, int *state_p)
{
struct acpi_device *device;
int state;
int result;
result = acpi_bus_get_device(handle, &device);
if (result)
if (device->power.state == ACPI_STATE_UNKNOWN) {
result = acpi_bus_init_power(device);
if (!result && state_p)
*state_p = device->power.state;
return result;
}
result = acpi_device_get_power(device, &state);
if (result)
@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
return 0;
}
int acpi_bus_update_power(acpi_handle handle, int *state_p)
{
struct acpi_device *device;
int result;
result = acpi_bus_get_device(handle, &device);
return result ? result : acpi_device_update_power(device, state_p);
}
EXPORT_SYMBOL_GPL(acpi_bus_update_power);
bool acpi_bus_power_manageable(acpi_handle handle)

View File

@ -32,8 +32,8 @@
#include <linux/jiffies.h>
#include <linux/stddef.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "internal.h"
#define PREFIX "ACPI: "
@ -323,14 +323,11 @@ static int dock_present(struct dock_station *ds)
*/
static void dock_create_acpi_device(acpi_handle handle)
{
struct acpi_device *device;
struct acpi_device *device = NULL;
int ret;
if (acpi_bus_get_device(handle, &device)) {
/*
* no device created for this object,
* so we should create one.
*/
acpi_bus_get_device(handle, &device);
if (!acpi_device_enumerated(device)) {
ret = acpi_bus_scan(handle);
if (ret)
pr_debug("error adding bus, %x\n", -ret);
@ -898,9 +895,6 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
void __init acpi_dock_init(void)
{
if (acpi_disabled)
return;
/* look for dock stations and bays */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);

View File

@ -39,10 +39,9 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <asm/io.h>
#include "internal.h"
@ -91,10 +90,6 @@ static unsigned int ec_storm_threshold __read_mostly = 8;
module_param(ec_storm_threshold, uint, 0644);
MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm");
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
typedef int (*acpi_ec_query_func) (void *data);
struct acpi_ec_query_handler {
struct list_head node;
acpi_ec_query_func func;
@ -387,27 +382,6 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
return acpi_ec_transaction(ec, &t);
}
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
int ec_burst_enable(void)
{
if (!first_ec)
return -ENODEV;
return acpi_ec_burst_enable(first_ec);
}
EXPORT_SYMBOL(ec_burst_enable);
int ec_burst_disable(void)
{
if (!first_ec)
return -ENODEV;
return acpi_ec_burst_disable(first_ec);
}
EXPORT_SYMBOL(ec_burst_disable);
int ec_read(u8 addr, u8 *val)
{
int err;
@ -779,9 +753,9 @@ static int ec_install_handlers(struct acpi_ec *ec)
pr_err("Fail in evaluating the _REG object"
" of EC device. Broken bios is suspected.\n");
} else {
acpi_disable_gpe(NULL, ec->gpe);
acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler);
acpi_disable_gpe(NULL, ec->gpe);
return -ENODEV;
}
}

View File

@ -105,7 +105,7 @@ static const struct file_operations acpi_ec_io_ops = {
.llseek = default_llseek,
};
int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
{
struct dentry *dev_dir;
char name[64];

View File

@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/gfp.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <net/netlink.h>
#include <net/genetlink.h>

View File

@ -29,8 +29,7 @@
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#define PREFIX "ACPI: "

View File

@ -37,7 +37,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
{
if (acpi_disabled)
return -ENODEV;
if (type && type->match && type->find_device) {
if (type && type->match && type->find_companion) {
down_write(&bus_type_sem);
list_add_tail(&type->list, &bus_type_list);
up_write(&bus_type_sem);
@ -82,109 +82,74 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
#define FIND_CHILD_MIN_SCORE 1
#define FIND_CHILD_MAX_SCORE 2
static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_p)
{
struct acpi_device *adev = NULL;
acpi_bus_get_device(handle, &adev);
if (adev) {
*ret_p = handle;
return AE_CTRL_TERMINATE;
}
return AE_OK;
}
static int do_find_child_checks(acpi_handle handle, bool is_bridge)
static int find_child_checks(struct acpi_device *adev, bool check_children)
{
bool sta_present = true;
unsigned long long sta;
acpi_status status;
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
if (status == AE_NOT_FOUND)
sta_present = false;
else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
return -ENODEV;
if (is_bridge) {
void *test = NULL;
if (check_children && list_empty(&adev->children))
return -ENODEV;
/* Check if this object has at least one child device. */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
acpi_dev_present, NULL, NULL, &test);
if (!test)
return -ENODEV;
}
return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
}
struct find_child_context {
u64 addr;
bool is_bridge;
acpi_handle ret;
int ret_score;
};
static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
void *data, void **not_used)
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
u64 address, bool check_children)
{
struct find_child_context *context = data;
unsigned long long addr;
acpi_status status;
int score;
struct acpi_device *adev, *ret = NULL;
int ret_score = 0;
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
if (ACPI_FAILURE(status) || addr != context->addr)
return AE_OK;
if (!parent)
return NULL;
if (!context->ret) {
/* This is the first matching object. Save its handle. */
context->ret = handle;
return AE_OK;
list_for_each_entry(adev, &parent->children, node) {
unsigned long long addr;
acpi_status status;
int score;
status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR,
NULL, &addr);
if (ACPI_FAILURE(status) || addr != address)
continue;
if (!ret) {
/* This is the first matching object. Save it. */
ret = adev;
continue;
}
/*
* There is more than one matching device object with the same
* _ADR value. That really is unexpected, so we are kind of
* beyond the scope of the spec here. We have to choose which
* one to return, though.
*
* First, check if the previously found object is good enough
* and return it if so. Second, do the same for the object that
* we've just found.
*/
if (!ret_score) {
ret_score = find_child_checks(ret, check_children);
if (ret_score == FIND_CHILD_MAX_SCORE)
return ret;
}
score = find_child_checks(adev, check_children);
if (score == FIND_CHILD_MAX_SCORE) {
return adev;
} else if (score > ret_score) {
ret = adev;
ret_score = score;
}
}
/*
* There is more than one matching object with the same _ADR value.
* That really is unexpected, so we are kind of beyond the scope of the
* spec here. We have to choose which one to return, though.
*
* First, check if the previously found object is good enough and return
* its handle if so. Second, check the same for the object that we've
* just found.
*/
if (!context->ret_score) {
score = do_find_child_checks(context->ret, context->is_bridge);
if (score == FIND_CHILD_MAX_SCORE)
return AE_CTRL_TERMINATE;
else
context->ret_score = score;
}
score = do_find_child_checks(handle, context->is_bridge);
if (score == FIND_CHILD_MAX_SCORE) {
context->ret = handle;
return AE_CTRL_TERMINATE;
} else if (score > context->ret_score) {
context->ret = handle;
context->ret_score = score;
}
return AE_OK;
return ret;
}
acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge)
{
if (parent) {
struct find_child_context context = {
.addr = addr,
.is_bridge = is_bridge,
};
acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child,
NULL, &context, NULL);
return context.ret;
}
return NULL;
}
EXPORT_SYMBOL_GPL(acpi_find_child);
EXPORT_SYMBOL_GPL(acpi_find_child_device);
static void acpi_physnode_link_name(char *buf, unsigned int node_id)
{
@ -195,9 +160,8 @@ static void acpi_physnode_link_name(char *buf, unsigned int node_id)
strcpy(buf, PHYSICAL_NODE_STRING);
}
int acpi_bind_one(struct device *dev, acpi_handle handle)
int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
{
struct acpi_device *acpi_dev = NULL;
struct acpi_device_physical_node *physical_node, *pn;
char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
struct list_head *physnode_list;
@ -205,14 +169,12 @@ int acpi_bind_one(struct device *dev, acpi_handle handle)
int retval = -EINVAL;
if (ACPI_COMPANION(dev)) {
if (handle) {
if (acpi_dev) {
dev_warn(dev, "ACPI companion already set\n");
return -EINVAL;
} else {
acpi_dev = ACPI_COMPANION(dev);
}
} else {
acpi_bus_get_device(handle, &acpi_dev);
}
if (!acpi_dev)
return -EINVAL;
@ -322,29 +284,22 @@ int acpi_unbind_one(struct device *dev)
}
EXPORT_SYMBOL_GPL(acpi_unbind_one);
void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr)
{
struct acpi_device *adev;
if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev))
ACPI_COMPANION_SET(dev, adev);
}
EXPORT_SYMBOL_GPL(acpi_preset_companion);
static int acpi_platform_notify(struct device *dev)
{
struct acpi_bus_type *type = acpi_get_bus_type(dev);
acpi_handle handle;
int ret;
ret = acpi_bind_one(dev, NULL);
if (ret && type) {
ret = type->find_device(dev, &handle);
if (ret) {
struct acpi_device *adev;
adev = type->find_companion(dev);
if (!adev) {
DBG("Unable to get handle for %s\n", dev_name(dev));
ret = -ENODEV;
goto out;
}
ret = acpi_bind_one(dev, handle);
ret = acpi_bind_one(dev, adev);
if (ret)
goto out;
}

View File

@ -25,8 +25,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/hed.h>
static struct acpi_device_id acpi_hed_ids[] = {

View File

@ -28,7 +28,6 @@ int init_acpi_device_notify(void);
int acpi_scan_init(void);
void acpi_pci_root_init(void);
void acpi_pci_link_init(void);
void acpi_pci_root_hp_init(void);
void acpi_processor_init(void);
void acpi_platform_init(void);
int acpi_sysfs_init(void);
@ -73,6 +72,9 @@ void acpi_lpss_init(void);
static inline void acpi_lpss_init(void) {}
#endif
bool acpi_queue_hotplug_work(struct work_struct *work);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
/* --------------------------------------------------------------------------
Device Node Initialization / Removal
-------------------------------------------------------------------------- */
@ -85,9 +87,9 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta);
void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
int acpi_bind_one(struct device *dev, acpi_handle handle);
int acpi_bind_one(struct device *dev, struct acpi_device *adev);
int acpi_unbind_one(struct device *dev);
void acpi_bus_device_eject(void *data, u32 ost_src);
bool acpi_device_is_present(struct acpi_device *adev);
/* --------------------------------------------------------------------------
Power Resource
@ -105,6 +107,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
int acpi_power_on_resources(struct acpi_device *device, int state);
int acpi_power_transition(struct acpi_device *device, int state);
int acpi_device_update_power(struct acpi_device *device, int *state_p);
int acpi_wakeup_device_init(void);
void acpi_early_processor_set_pdc(void);
@ -127,12 +131,21 @@ struct acpi_ec {
extern struct acpi_ec *first_ec;
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
typedef int (*acpi_ec_query_func) (void *data);
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
void acpi_ec_block_transactions(void);
void acpi_ec_unblock_transactions(void);
void acpi_ec_unblock_transactions_early(void);
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
acpi_handle handle, acpi_ec_query_func func,
void *data);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
/*--------------------------------------------------------------------------
Suspend/Resume

View File

@ -29,7 +29,6 @@
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/numa.h>
#include <acpi/acpi_bus.h>
#define PREFIX "ACPI: "

View File

@ -12,7 +12,8 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/acpi_io.h>
#include "internal.h"
/* ACPI NVS regions, APEI may use it */

View File

@ -39,7 +39,6 @@
#include <linux/workqueue.h>
#include <linux/nmi.h>
#include <linux/acpi.h>
#include <linux/acpi_io.h>
#include <linux/efi.h>
#include <linux/ioport.h>
#include <linux/list.h>
@ -49,9 +48,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
#include "internal.h"
#define _COMPONENT ACPI_OS_SERVICES
@ -544,7 +540,7 @@ static u64 acpi_tables_addr;
static int all_tables_size;
/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
u8 __init acpi_table_checksum(u8 *buffer, u32 length)
static u8 __init acpi_table_checksum(u8 *buffer, u32 length)
{
u8 sum = 0;
u8 *end = buffer + length;
@ -1215,6 +1211,10 @@ acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
return AE_OK;
}
bool acpi_queue_hotplug_work(struct work_struct *work)
{
return queue_work(kacpi_hotplug_wq, work);
}
acpi_status
acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
@ -1282,7 +1282,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
jiffies = MAX_SCHEDULE_TIMEOUT;
else
jiffies = msecs_to_jiffies(timeout);
ret = down_timeout(sem, jiffies);
if (ret)
status = AE_TIME;
@ -1794,7 +1794,7 @@ acpi_status __init acpi_os_initialize1(void)
{
kacpid_wq = alloc_workqueue("kacpid", 0, 1);
kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1);
kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);

View File

@ -37,8 +37,6 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#define PREFIX "ACPI: "

View File

@ -39,9 +39,9 @@
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "internal.h"
#define PREFIX "ACPI: "

View File

@ -35,9 +35,7 @@
#include <linux/pci-aspm.h>
#include <linux/acpi.h>
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/apei.h>
#include <acpi/apei.h> /* for acpi_hest_init() */
#include "internal.h"
@ -51,6 +49,12 @@ static int acpi_pci_root_add(struct acpi_device *device,
const struct acpi_device_id *not_used);
static void acpi_pci_root_remove(struct acpi_device *device);
static int acpi_pci_root_scan_dependent(struct acpi_device *adev)
{
acpiphp_check_host_bridge(adev->handle);
return 0;
}
#define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \
| OSC_PCI_ASPM_SUPPORT \
| OSC_PCI_CLOCK_PM_SUPPORT \
@ -66,7 +70,8 @@ static struct acpi_scan_handler pci_root_handler = {
.attach = acpi_pci_root_add,
.detach = acpi_pci_root_remove,
.hotplug = {
.ignore = true,
.enabled = true,
.scan_dependent = acpi_pci_root_scan_dependent,
},
};
@ -630,116 +635,9 @@ static void acpi_pci_root_remove(struct acpi_device *device)
void __init acpi_pci_root_init(void)
{
acpi_hest_init();
if (!acpi_pci_disabled) {
pci_acpi_crs_quirks();
acpi_scan_add_handler(&pci_root_handler);
}
}
/* Support root bridge hotplug */
static void handle_root_bridge_insertion(acpi_handle handle)
{
struct acpi_device *device;
if (!acpi_bus_get_device(handle, &device)) {
dev_printk(KERN_DEBUG, &device->dev,
"acpi device already exists; ignoring notify\n");
if (acpi_pci_disabled)
return;
}
if (acpi_bus_scan(handle))
acpi_handle_err(handle, "cannot add bridge to acpi list\n");
}
static void hotplug_event_root(void *data, u32 type)
{
acpi_handle handle = data;
struct acpi_pci_root *root;
acpi_scan_lock_acquire();
root = acpi_pci_find_root(handle);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus enumerate */
acpi_handle_printk(KERN_DEBUG, handle,
"Bus check notify on %s\n", __func__);
if (root)
acpiphp_check_host_bridge(handle);
else
handle_root_bridge_insertion(handle);
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
acpi_handle_printk(KERN_DEBUG, handle,
"Device check notify on %s\n", __func__);
if (!root)
handle_root_bridge_insertion(handle);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
acpi_handle_printk(KERN_DEBUG, handle,
"Device eject notify on %s\n", __func__);
if (!root)
break;
get_device(&root->device->dev);
acpi_scan_lock_release();
acpi_bus_device_eject(root->device, ACPI_NOTIFY_EJECT_REQUEST);
return;
default:
acpi_handle_warn(handle,
"notify_handler: unknown event type 0x%x\n",
type);
break;
}
acpi_scan_lock_release();
}
static void handle_hotplug_event_root(acpi_handle handle, u32 type,
void *context)
{
acpi_hotplug_execute(hotplug_event_root, handle, type);
}
static acpi_status __init
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
int *count = (int *)context;
if (!acpi_is_root_bridge(handle))
return AE_OK;
(*count)++;
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_root, NULL);
if (ACPI_FAILURE(status))
acpi_handle_printk(KERN_DEBUG, handle,
"notify handler is not installed, exit status: %u\n",
(unsigned int)status);
else
acpi_handle_printk(KERN_DEBUG, handle,
"notify handler is installed\n");
return AE_OK;
}
void __init acpi_pci_root_hp_init(void)
{
int num = 0;
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
printk(KERN_DEBUG "Found %d acpi root devices\n", num);
pci_acpi_crs_quirks();
acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root");
}

View File

@ -35,6 +35,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/pci-acpi.h>
static bool debug;
static int check_sta_before_sun;

View File

@ -42,8 +42,7 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/sysfs.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include "sleep.h"
#include "internal.h"

View File

@ -3,12 +3,11 @@
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/bcd.h>
#include <linux/acpi.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "sleep.h"
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT

View File

@ -10,8 +10,7 @@
#include <linux/export.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#include "internal.h"

View File

@ -224,9 +224,9 @@ static int __acpi_processor_start(struct acpi_device *device)
static int acpi_processor_start(struct device *dev)
{
struct acpi_device *device;
struct acpi_device *device = ACPI_COMPANION(dev);
if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
if (!device)
return -ENODEV;
return __acpi_processor_start(device);
@ -234,10 +234,10 @@ static int acpi_processor_start(struct device *dev)
static int acpi_processor_stop(struct device *dev)
{
struct acpi_device *device;
struct acpi_device *device = ACPI_COMPANION(dev);
struct acpi_processor *pr;
if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
if (!device)
return 0;
acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,

View File

@ -35,6 +35,7 @@
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/syscore_ops.h>
#include <acpi/processor.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
@ -46,9 +47,6 @@
#include <asm/apic.h>
#endif
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"
@ -213,7 +211,7 @@ static int acpi_processor_suspend(void)
static void acpi_processor_resume(void)
{
u32 resumed_bm_rld;
u32 resumed_bm_rld = 0;
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
if (resumed_bm_rld == saved_bm_rld)
@ -598,7 +596,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
case ACPI_STATE_C2:
if (!cx->address)
break;
cx->valid = 1;
cx->valid = 1;
break;
case ACPI_STATE_C3:
@ -780,6 +778,13 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
if (unlikely(!pr))
return -EINVAL;
#ifdef CONFIG_HOTPLUG_CPU
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst &&
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START);
#endif
/*
* Must be done before busmaster disable as we might need to
* access HPET !
@ -821,6 +826,13 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (unlikely(!pr))
return -EINVAL;
#ifdef CONFIG_HOTPLUG_CPU
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst &&
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START);
#endif
if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
if (drv->safe_state_index >= 0) {
return drv->states[drv->safe_state_index].enter(dev,
@ -917,12 +929,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
if (!cx->valid)
continue;
#ifdef CONFIG_HOTPLUG_CPU
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst &&
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
continue;
#endif
per_cpu(acpi_cstate[count], dev->cpu) = cx;
count++;
@ -930,8 +936,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
break;
}
dev->state_count = count;
if (!count)
return -EINVAL;
@ -972,13 +976,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
if (!cx->valid)
continue;
#ifdef CONFIG_HOTPLUG_CPU
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst &&
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
continue;
#endif
state = &drv->states[count];
snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);

View File

@ -31,15 +31,12 @@
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#ifdef CONFIG_X86
#include <asm/cpufeature.h>
#endif
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"

View File

@ -30,12 +30,9 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#include <acpi/acpi_drivers.h>
#include <asm/uaccess.h>
#define PREFIX "ACPI: "
@ -186,14 +183,14 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
#endif
/* thermal coolign device callbacks */
/* thermal cooling device callbacks */
static int acpi_processor_max_state(struct acpi_processor *pr)
{
int max_state = 0;
/*
* There exists four states according to
* cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
* cpufreq_thermal_reduction_pctg. 0, 1, 2, 3
*/
max_state += cpufreq_get_max_state(pr->id);
if (pr->flags.throttling)

View File

@ -32,14 +32,11 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"

View File

@ -8,8 +8,7 @@
* the Free Software Foundation version 2.
*/
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/delay.h>

View File

@ -12,13 +12,12 @@
#include <linux/dmi.h>
#include <linux/nls.h>
#include <acpi/acpi_drivers.h>
#include <asm/pgtable.h>
#include "internal.h"
#define _COMPONENT ACPI_BUS_COMPONENT
ACPI_MODULE_NAME("scan");
#define STRUCT_TO_INT(s) (*((int*)&s))
extern struct acpi_device *acpi_root;
#define ACPI_BUS_CLASS "system_bus"
@ -27,6 +26,8 @@ extern struct acpi_device *acpi_root;
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page)
/*
* If set, devices will be hot-removed even if they cannot be put offline
* gracefully (from the kernel's standpoint).
@ -85,6 +86,9 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
* Creates hid/cid(s) string needed for modalias and uevent
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
* char *modalias: "acpi:IBM0001:ACPI0001"
* Return: 0: no _HID and no _CID
* -EINVAL: output error
* -ENOMEM: output is truncated
*/
static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
int size)
@ -101,8 +105,10 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0 || count >= size)
return -EINVAL;
if (count < 0)
return EINVAL;
if (count >= size)
return -ENOMEM;
len += count;
size -= count;
}
@ -111,20 +117,96 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
return len;
}
/*
* Creates uevent modalias field for ACPI enumerated devices.
* Because the other buses does not support ACPI HIDs & CIDs.
* e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
* "acpi:IBM0001:ACPI0001"
*/
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
{
struct acpi_device *acpi_dev;
int len;
acpi_dev = ACPI_COMPANION(dev);
if (!acpi_dev)
return -ENODEV;
/* Fall back to bus specific way of modalias exporting */
if (list_empty(&acpi_dev->pnp.ids))
return -ENODEV;
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen);
if (len <= 0)
return len;
env->buflen += len;
return 0;
}
EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
/*
* Creates modalias sysfs attribute for ACPI enumerated devices.
* Because the other buses does not support ACPI HIDs & CIDs.
* e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
* "acpi:IBM0001:ACPI0001"
*/
int acpi_device_modalias(struct device *dev, char *buf, int size)
{
struct acpi_device *acpi_dev;
int len;
acpi_dev = ACPI_COMPANION(dev);
if (!acpi_dev)
return -ENODEV;
/* Fall back to bus specific way of modalias exporting */
if (list_empty(&acpi_dev->pnp.ids))
return -ENODEV;
len = create_modalias(acpi_dev, buf, size -1);
if (len <= 0)
return len;
buf[len++] = '\n';
return len;
}
EXPORT_SYMBOL_GPL(acpi_device_modalias);
static ssize_t
acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct acpi_device *acpi_dev = to_acpi_device(dev);
int len;
/* Device has no HID and no CID or string is >1024 */
len = create_modalias(acpi_dev, buf, 1024);
if (len <= 0)
return 0;
return len;
buf[len++] = '\n';
return len;
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent)
{
struct acpi_device_physical_node *pn;
bool offline = true;
mutex_lock(&adev->physical_node_lock);
list_for_each_entry(pn, &adev->physical_node_list, node)
if (device_supports_offline(pn->dev) && !pn->dev->offline) {
if (uevent)
kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE);
offline = false;
break;
}
mutex_unlock(&adev->physical_node_lock);
return offline;
}
static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data,
void **ret_p)
{
@ -195,19 +277,11 @@ static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data,
return AE_OK;
}
static int acpi_scan_hot_remove(struct acpi_device *device)
static int acpi_scan_try_to_offline(struct acpi_device *device)
{
acpi_handle handle = device->handle;
struct device *errdev;
struct device *errdev = NULL;
acpi_status status;
unsigned long long sta;
/* If there is no handle, the device node has been unregistered. */
if (!handle) {
dev_dbg(&device->dev, "ACPI handle missing\n");
put_device(&device->dev);
return -EINVAL;
}
/*
* Carry out two passes here and ignore errors in the first pass,
@ -218,7 +292,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
*
* If the first pass is successful, the second one isn't needed, though.
*/
errdev = NULL;
status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
NULL, acpi_bus_offline, (void *)false,
(void **)&errdev);
@ -226,7 +299,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
dev_warn(errdev, "Offline disabled.\n");
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_online, NULL, NULL, NULL);
put_device(&device->dev);
return -EPERM;
}
acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev);
@ -245,20 +317,32 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
acpi_walk_namespace(ACPI_TYPE_ANY, handle,
ACPI_UINT32_MAX, acpi_bus_online,
NULL, NULL, NULL);
put_device(&device->dev);
return -EBUSY;
}
}
return 0;
}
static int acpi_scan_hot_remove(struct acpi_device *device)
{
acpi_handle handle = device->handle;
unsigned long long sta;
acpi_status status;
if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) {
if (!acpi_scan_is_offline(device, true))
return -EBUSY;
} else {
int error = acpi_scan_try_to_offline(device);
if (error)
return error;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Hot-removing device %s...\n", dev_name(&device->dev)));
acpi_bus_trim(device);
/* Device node has been unregistered. */
put_device(&device->dev);
device = NULL;
acpi_evaluate_lck(handle, 0);
/*
* TBD: _EJD support.
@ -285,115 +369,127 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
return 0;
}
void acpi_bus_device_eject(void *data, u32 ost_src)
static int acpi_scan_device_not_present(struct acpi_device *adev)
{
struct acpi_device *device = data;
acpi_handle handle = device->handle;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
int error;
lock_device_hotplug();
mutex_lock(&acpi_scan_lock);
if (ost_src == ACPI_NOTIFY_EJECT_REQUEST)
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
error = acpi_scan_hot_remove(device);
if (error == -EPERM) {
goto err_support;
} else if (error) {
goto err_out;
if (!acpi_device_enumerated(adev)) {
dev_warn(&adev->dev, "Still not present\n");
return -EALREADY;
}
out:
mutex_unlock(&acpi_scan_lock);
unlock_device_hotplug();
return;
err_support:
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
err_out:
acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL);
goto out;
acpi_bus_trim(adev);
return 0;
}
static void acpi_scan_bus_device_check(void *data, u32 ost_source)
static int acpi_scan_device_check(struct acpi_device *adev)
{
acpi_handle handle = data;
struct acpi_device *device = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
int error;
lock_device_hotplug();
mutex_lock(&acpi_scan_lock);
if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
acpi_bus_get_device(handle, &device);
if (device) {
dev_warn(&device->dev, "Attempt to re-insert\n");
goto out;
acpi_bus_get_status(adev);
if (adev->status.present || adev->status.functional) {
/*
* This function is only called for device objects for which
* matching scan handlers exist. The only situation in which
* the scan handler is not attached to this device object yet
* is when the device has just appeared (either it wasn't
* present at all before or it was removed and then added
* again).
*/
if (adev->handler) {
dev_warn(&adev->dev, "Already enumerated\n");
return -EALREADY;
}
error = acpi_bus_scan(adev->handle);
if (error) {
dev_warn(&adev->dev, "Namespace scan failure\n");
return error;
}
if (!adev->handler) {
dev_warn(&adev->dev, "Enumeration failure\n");
error = -ENODEV;
}
} else {
error = acpi_scan_device_not_present(adev);
}
error = acpi_bus_scan(handle);
if (error) {
acpi_handle_warn(handle, "Namespace scan failure\n");
goto out;
}
error = acpi_bus_get_device(handle, &device);
if (error) {
acpi_handle_warn(handle, "Missing device node object\n");
goto out;
}
ost_code = ACPI_OST_SC_SUCCESS;
if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
out:
acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
mutex_unlock(&acpi_scan_lock);
unlock_device_hotplug();
return error;
}
static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
static int acpi_scan_bus_check(struct acpi_device *adev)
{
u32 ost_status;
struct acpi_scan_handler *handler = adev->handler;
struct acpi_device *child;
int error;
switch (type) {
acpi_bus_get_status(adev);
if (!(adev->status.present || adev->status.functional)) {
acpi_scan_device_not_present(adev);
return 0;
}
if (handler && handler->hotplug.scan_dependent)
return handler->hotplug.scan_dependent(adev);
error = acpi_bus_scan(adev->handle);
if (error) {
dev_warn(&adev->dev, "Namespace scan failure\n");
return error;
}
list_for_each_entry(child, &adev->children, node) {
error = acpi_scan_bus_check(child);
if (error)
return error;
}
return 0;
}
static void acpi_device_hotplug(void *data, u32 src)
{
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_device *adev = data;
int error;
lock_device_hotplug();
mutex_lock(&acpi_scan_lock);
/*
* The device object's ACPI handle cannot become invalid as long as we
* are holding acpi_scan_lock, but it may have become invalid before
* that lock was acquired.
*/
if (adev->handle == INVALID_ACPI_HANDLE)
goto out;
switch (src) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle,
"ACPI_NOTIFY_BUS_CHECK event: unsupported\n");
ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
error = acpi_scan_bus_check(adev);
break;
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle,
"ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n");
ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
error = acpi_scan_device_check(adev);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle,
"ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n");
ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
case ACPI_OST_EC_OSPM_EJECT:
error = acpi_scan_hot_remove(adev);
break;
default:
/* non-hotplug event; possibly handled by other handler */
return;
error = -EINVAL;
break;
}
if (!error)
ost_code = ACPI_OST_SC_SUCCESS;
acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL);
out:
acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
put_device(&adev->dev);
mutex_unlock(&acpi_scan_lock);
unlock_device_hotplug();
}
static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
{
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_scan_handler *handler = data;
struct acpi_device *adev;
acpi_status status;
if (!handler->hotplug.enabled)
return acpi_hotplug_unsupported(handle, type);
if (acpi_bus_get_device(handle, &adev))
goto err_out;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
@ -404,27 +500,27 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
break;
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
if (acpi_bus_get_device(handle, &adev))
if (!handler->hotplug.enabled) {
acpi_handle_err(handle, "Eject disabled\n");
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
goto err_out;
get_device(&adev->dev);
status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type);
if (ACPI_SUCCESS(status))
return;
put_device(&adev->dev);
goto err_out;
}
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
break;
default:
/* non-hotplug event; possibly handled by other handler */
return;
}
status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type);
get_device(&adev->dev);
status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
if (ACPI_SUCCESS(status))
return;
put_device(&adev->dev);
err_out:
acpi_evaluate_hotplug_ost(handle, type,
ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
}
static ssize_t real_power_state_show(struct device *dev,
@ -475,7 +571,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
get_device(&acpi_device->dev);
status = acpi_hotplug_execute(acpi_bus_device_eject, acpi_device,
status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
ACPI_OST_EC_OSPM_EJECT);
if (ACPI_SUCCESS(status))
return count;
@ -567,6 +663,20 @@ acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *buf) {
struct acpi_device *acpi_dev = to_acpi_device(dev);
acpi_status status;
unsigned long long sta;
status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
return sprintf(buf, "%llu\n", sta);
}
static DEVICE_ATTR_RO(status);
static int acpi_device_setup_files(struct acpi_device *dev)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@ -622,6 +732,12 @@ static int acpi_device_setup_files(struct acpi_device *dev)
dev->pnp.sun = (unsigned long)-1;
}
if (acpi_has_method(dev->handle, "_STA")) {
result = device_create_file(&dev->dev, &dev_attr_status);
if (result)
goto end;
}
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
* hot-removal function from userland.
@ -677,6 +793,8 @@ static void acpi_device_remove_files(struct acpi_device *dev)
device_remove_file(&dev->dev, &dev_attr_adr);
device_remove_file(&dev->dev, &dev_attr_modalias);
device_remove_file(&dev->dev, &dev_attr_hid);
if (acpi_has_method(dev->handle, "_STA"))
device_remove_file(&dev->dev, &dev_attr_status);
if (dev->handle)
device_remove_file(&dev->dev, &dev_attr_path);
}
@ -782,8 +900,8 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
return -ENOMEM;
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen);
if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
if (len <= 0)
return len;
env->buflen += len;
return 0;
}
@ -907,9 +1025,91 @@ struct bus_type acpi_bus_type = {
.uevent = acpi_device_uevent,
};
static void acpi_bus_data_handler(acpi_handle handle, void *context)
static void acpi_device_del(struct acpi_device *device)
{
/* Intentionally empty. */
mutex_lock(&acpi_device_lock);
if (device->parent)
list_del(&device->node);
list_del(&device->wakeup_list);
mutex_unlock(&acpi_device_lock);
acpi_power_add_remove_device(device, false);
acpi_device_remove_files(device);
if (device->remove)
device->remove(device);
device_del(&device->dev);
}
static LIST_HEAD(acpi_device_del_list);
static DEFINE_MUTEX(acpi_device_del_lock);
static void acpi_device_del_work_fn(struct work_struct *work_not_used)
{
for (;;) {
struct acpi_device *adev;
mutex_lock(&acpi_device_del_lock);
if (list_empty(&acpi_device_del_list)) {
mutex_unlock(&acpi_device_del_lock);
break;
}
adev = list_first_entry(&acpi_device_del_list,
struct acpi_device, del_list);
list_del(&adev->del_list);
mutex_unlock(&acpi_device_del_lock);
acpi_device_del(adev);
/*
* Drop references to all power resources that might have been
* used by the device.
*/
acpi_power_transition(adev, ACPI_STATE_D3_COLD);
put_device(&adev->dev);
}
}
/**
* acpi_scan_drop_device - Drop an ACPI device object.
* @handle: Handle of an ACPI namespace node, not used.
* @context: Address of the ACPI device object to drop.
*
* This is invoked by acpi_ns_delete_node() during the removal of the ACPI
* namespace node the device object pointed to by @context is attached to.
*
* The unregistration is carried out asynchronously to avoid running
* acpi_device_del() under the ACPICA's namespace mutex and the list is used to
* ensure the correct ordering (the device objects must be unregistered in the
* same order in which the corresponding namespace nodes are deleted).
*/
static void acpi_scan_drop_device(acpi_handle handle, void *context)
{
static DECLARE_WORK(work, acpi_device_del_work_fn);
struct acpi_device *adev = context;
mutex_lock(&acpi_device_del_lock);
/*
* Use the ACPI hotplug workqueue which is ordered, so this work item
* won't run after any hotplug work items submitted subsequently. That
* prevents attempts to register device objects identical to those being
* deleted from happening concurrently (such attempts result from
* hotplug events handled via the ACPI hotplug workqueue). It also will
* run after all of the work items submitted previosuly, which helps
* those work items to ensure that they are not accessing stale device
* objects.
*/
if (list_empty(&acpi_device_del_list))
acpi_queue_hotplug_work(&work);
list_add_tail(&adev->del_list, &acpi_device_del_list);
/* Make acpi_ns_validate_handle() return NULL for this handle. */
adev->handle = INVALID_ACPI_HANDLE;
mutex_unlock(&acpi_device_del_lock);
}
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
@ -919,7 +1119,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
if (!device)
return -EINVAL;
status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
if (ACPI_FAILURE(status) || !*device) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
handle));
@ -939,7 +1139,7 @@ int acpi_device_add(struct acpi_device *device,
if (device->handle) {
acpi_status status;
status = acpi_attach_data(device->handle, acpi_bus_data_handler,
status = acpi_attach_data(device->handle, acpi_scan_drop_device,
device);
if (ACPI_FAILURE(status)) {
acpi_handle_err(device->handle,
@ -957,6 +1157,7 @@ int acpi_device_add(struct acpi_device *device,
INIT_LIST_HEAD(&device->node);
INIT_LIST_HEAD(&device->wakeup_list);
INIT_LIST_HEAD(&device->physical_node_list);
INIT_LIST_HEAD(&device->del_list);
mutex_init(&device->physical_node_lock);
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
@ -1020,37 +1221,10 @@ int acpi_device_add(struct acpi_device *device,
mutex_unlock(&acpi_device_lock);
err_detach:
acpi_detach_data(device->handle, acpi_bus_data_handler);
acpi_detach_data(device->handle, acpi_scan_drop_device);
return result;
}
static void acpi_device_unregister(struct acpi_device *device)
{
mutex_lock(&acpi_device_lock);
if (device->parent)
list_del(&device->node);
list_del(&device->wakeup_list);
mutex_unlock(&acpi_device_lock);
acpi_detach_data(device->handle, acpi_bus_data_handler);
acpi_power_add_remove_device(device, false);
acpi_device_remove_files(device);
if (device->remove)
device->remove(device);
device_del(&device->dev);
/*
* Transition the device to D3cold to drop the reference counts of all
* power resources the device depends on and turn off the ones that have
* no more references.
*/
acpi_device_set_power(device, ACPI_STATE_D3_COLD);
device->handle = NULL;
put_device(&device->dev);
}
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
@ -1624,11 +1798,13 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
STRUCT_TO_INT(device->status) = sta;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
device->flags.visited = false;
device_initialize(&device->dev);
dev_set_uevent_suppress(&device->dev, true);
}
@ -1713,6 +1889,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
return 0;
}
bool acpi_device_is_present(struct acpi_device *adev)
{
if (adev->status.present || adev->status.functional)
return true;
adev->flags.initialized = false;
return false;
}
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
char *idstr,
const struct acpi_device_id **matchid)
@ -1772,7 +1957,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type)
*/
list_for_each_entry(hwid, &pnp.ids, list) {
handler = acpi_scan_match_handler(hwid->id, NULL);
if (handler && !handler->hotplug.ignore) {
if (handler) {
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_hotplug_notify_cb, handler);
break;
@ -1806,18 +1991,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
acpi_scan_init_hotplug(handle, type);
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
struct acpi_device_wakeup wakeup;
if (acpi_has_method(handle, "_PRW")) {
acpi_bus_extract_wakeup_device_power_package(handle,
&wakeup);
acpi_power_resources_list_free(&wakeup.resources);
}
return AE_CTRL_DEPTH;
}
acpi_add_single_object(&device, handle, type, sta);
if (!device)
return AE_CTRL_DEPTH;
@ -1852,36 +2025,40 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
return ret;
}
static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_not_used)
static void acpi_bus_attach(struct acpi_device *device)
{
struct acpi_device *device;
unsigned long long sta_not_used;
struct acpi_device *child;
int ret;
/*
* Ignore errors ignored by acpi_bus_check_add() to avoid terminating
* namespace walks prematurely.
*/
if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
return AE_OK;
if (acpi_bus_get_device(handle, &device))
return AE_CTRL_DEPTH;
acpi_bus_get_status(device);
/* Skip devices that are not present. */
if (!acpi_device_is_present(device)) {
device->flags.visited = false;
return;
}
if (device->handler)
return AE_OK;
goto ok;
if (!device->flags.initialized) {
acpi_bus_update_power(device, NULL);
device->flags.initialized = true;
}
device->flags.visited = false;
ret = acpi_scan_attach_handler(device);
if (ret < 0)
return AE_CTRL_DEPTH;
return;
device->flags.match_driver = true;
if (ret > 0)
return AE_OK;
if (!ret) {
ret = device_attach(&device->dev);
if (ret < 0)
return;
}
device->flags.visited = true;
ret = device_attach(&device->dev);
return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
ok:
list_for_each_entry(child, &device->children, node)
acpi_bus_attach(child);
}
/**
@ -1901,75 +2078,48 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
int acpi_bus_scan(acpi_handle handle)
{
void *device = NULL;
int error = 0;
if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, NULL, NULL, &device);
if (!device)
error = -ENODEV;
else if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL)))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_device_attach, NULL, NULL, NULL);
return error;
if (device) {
acpi_bus_attach(device);
return 0;
}
return -ENODEV;
}
EXPORT_SYMBOL(acpi_bus_scan);
static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_not_used)
{
struct acpi_device *device = NULL;
if (!acpi_bus_get_device(handle, &device)) {
struct acpi_scan_handler *dev_handler = device->handler;
if (dev_handler) {
if (dev_handler->detach)
dev_handler->detach(device);
device->handler = NULL;
} else {
device_release_driver(&device->dev);
}
}
return AE_OK;
}
static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_not_used)
{
struct acpi_device *device = NULL;
if (!acpi_bus_get_device(handle, &device))
acpi_device_unregister(device);
return AE_OK;
}
/**
* acpi_bus_trim - Remove ACPI device node and all of its descendants
* @start: Root of the ACPI device nodes subtree to remove.
* acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
* @adev: Root of the ACPI namespace scope to walk.
*
* Must be called under acpi_scan_lock.
*/
void acpi_bus_trim(struct acpi_device *start)
void acpi_bus_trim(struct acpi_device *adev)
{
struct acpi_scan_handler *handler = adev->handler;
struct acpi_device *child;
list_for_each_entry_reverse(child, &adev->children, node)
acpi_bus_trim(child);
if (handler) {
if (handler->detach)
handler->detach(adev);
adev->handler = NULL;
} else {
device_release_driver(&adev->dev);
}
/*
* Execute acpi_bus_device_detach() as a post-order callback to detach
* all ACPI drivers from the device nodes being removed.
* Most likely, the device is going away, so put it into D3cold before
* that.
*/
acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
acpi_bus_device_detach, NULL, NULL);
acpi_bus_device_detach(start->handle, 0, NULL, NULL);
/*
* Execute acpi_bus_remove() as a post-order callback to remove device
* nodes in the given namespace scope.
*/
acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
acpi_bus_remove, NULL, NULL);
acpi_bus_remove(start->handle, 0, NULL, NULL);
acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
adev->flags.initialized = false;
adev->flags.visited = false;
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
@ -2047,14 +2197,14 @@ int __init acpi_scan_init(void)
result = acpi_bus_scan_fixed();
if (result) {
acpi_device_unregister(acpi_root);
acpi_detach_data(acpi_root->handle, acpi_scan_drop_device);
acpi_device_del(acpi_root);
put_device(&acpi_root->dev);
goto out;
}
acpi_update_all_gpes();
acpi_pci_root_hp_init();
out:
mutex_unlock(&acpi_scan_lock);
return result;

View File

@ -18,12 +18,8 @@
#include <linux/reboot.h>
#include <linux/acpi.h>
#include <linux/module.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "internal.h"
#include "sleep.h"
@ -670,11 +666,8 @@ static void acpi_hibernation_leave(void)
/* Reprogram control registers */
acpi_leave_sleep_state_prep(ACPI_STATE_S4);
/* Check the hardware signature */
if (facs && s4_hardware_signature != facs->hardware_signature) {
printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
"cannot resume!\n");
panic("ACPI S4 hardware signature mismatch");
}
if (facs && s4_hardware_signature != facs->hardware_signature)
pr_crit("ACPI: Hardware changed while hibernated, success doubtful!\n");
/* Restore the NVS memory area */
suspend_nvs_restore();
/* Allow EC transactions to happen. */
@ -806,9 +799,6 @@ int __init acpi_sleep_init(void)
char *pos = supported;
int i;
if (acpi_disabled)
return 0;
acpi_sleep_dmi_check();
sleep_states[ACPI_STATE_S0] = 1;

View File

@ -5,7 +5,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include "internal.h"

View File

@ -278,12 +278,13 @@ acpi_table_parse_madt(enum acpi_madt_type id,
/**
* acpi_table_parse - find table with @id, run @handler on it
*
* @id: table id to find
* @handler: handler to run
*
* Scan the ACPI System Descriptor Table (STD) for a table matching @id,
* run @handler on it. Return 0 if table found, return on if not.
* run @handler on it.
*
* Return 0 if table found, -errno if not.
*/
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
{
@ -293,7 +294,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
if (acpi_disabled)
return -ENODEV;
if (!handler)
if (!id || !handler)
return -EINVAL;
if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
@ -306,7 +307,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
early_acpi_os_unmap_memory(table, tbl_size);
return 0;
} else
return 1;
return -ENODEV;
}
/*
@ -351,7 +352,7 @@ int __init acpi_table_init(void)
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
if (ACPI_FAILURE(status))
return 1;
return -EINVAL;
check_multiple_madt();
return 0;

View File

@ -41,10 +41,9 @@
#include <linux/kmod.h>
#include <linux/reboot.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <asm/uaccess.h>
#define PREFIX "ACPI: "
@ -862,7 +861,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
return acpi_thermal_cooling_device_cb(thermal, cdev, false);
}
static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.bind = acpi_thermal_bind_cooling_device,
.unbind = acpi_thermal_unbind_cooling_device,
.get_temp = thermal_get_temp,

View File

@ -30,8 +30,6 @@
#include <linux/types.h>
#include <linux/hardirq.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "internal.h"
@ -574,3 +572,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
return status;
}
/**
* acpi_evaluate_dsm - evaluate device's _DSM method
* @handle: ACPI device handle
* @uuid: UUID of requested functions, should be 16 bytes
* @rev: revision number of requested function
* @func: requested function number
* @argv4: the function specific parameter
*
* Evaluate device's _DSM method with specified UUID, revision id and
* function number. Caller needs to free the returned object.
*
* Though ACPI defines the fourth parameter for _DSM should be a package,
* some old BIOSes do expect a buffer or an integer etc.
*/
union acpi_object *
acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func,
union acpi_object *argv4)
{
acpi_status ret;
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object params[4];
struct acpi_object_list input = {
.count = 4,
.pointer = params,
};
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = 16;
params[0].buffer.pointer = (char *)uuid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = rev;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = func;
if (argv4) {
params[3] = *argv4;
} else {
params[3].type = ACPI_TYPE_PACKAGE;
params[3].package.count = 0;
params[3].package.elements = NULL;
}
ret = acpi_evaluate_object(handle, "_DSM", &input, &buf);
if (ACPI_SUCCESS(ret))
return (union acpi_object *)buf.pointer;
if (ret != AE_NOT_FOUND)
acpi_handle_warn(handle,
"failed to evaluate _DSM (0x%x)\n", ret);
return NULL;
}
EXPORT_SYMBOL(acpi_evaluate_dsm);
/**
* acpi_check_dsm - check if _DSM method supports requested functions.
* @handle: ACPI device handle
* @uuid: UUID of requested functions, should be 16 bytes at least
* @rev: revision number of requested functions
* @funcs: bitmap of requested functions
* @exclude: excluding special value, used to support i915 and nouveau
*
* Evaluate device's _DSM method to check whether it supports requested
* functions. Currently only support 64 functions at maximum, should be
* enough for now.
*/
bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
{
int i;
u64 mask = 0;
union acpi_object *obj;
if (funcs == 0)
return false;
obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL);
if (!obj)
return false;
/* For compatibility, old BIOSes may return an integer */
if (obj->type == ACPI_TYPE_INTEGER)
mask = obj->integer.value;
else if (obj->type == ACPI_TYPE_BUFFER)
for (i = 0; i < obj->buffer.length && i < 8; i++)
mask |= (((u8)obj->buffer.pointer[i]) << (i * 8));
ACPI_FREE(obj);
/*
* Bit 0 indicates whether there's support for any functions other than
* function 0 for the specified UUID and revision.
*/
if ((mask & 0x1) && (mask & funcs) == funcs)
return true;
return false;
}
EXPORT_SYMBOL(acpi_check_dsm);

View File

@ -37,12 +37,11 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/suspend.h>
#include <linux/acpi.h>
#include <acpi/video.h>
#include <asm/uaccess.h>
#include "internal.h"

View File

@ -50,7 +50,7 @@ static bool acpi_video_caps_checked;
static acpi_status
acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
void **retyurn_value)
void **return_value)
{
long *cap = context;

View File

@ -5,7 +5,6 @@
#include <linux/init.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <linux/kernel.h>
#include <linux/types.h>

View File

@ -20,8 +20,6 @@
#include <scsi/scsi_device.h>
#include "libata.h"
#include <acpi/acpi_bus.h>
unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)");
@ -180,12 +178,12 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle)
if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
acpi_preset_companion(&ap->tdev, host_handle, ap->port_no);
acpi_preset_companion(&ap->tdev, host_companion, ap->port_no);
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
@ -198,17 +196,17 @@ void ata_acpi_bind_port(struct ata_port *ap)
void ata_acpi_bind_dev(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
acpi_handle port_handle = ACPI_HANDLE(&ap->tdev);
acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
acpi_handle parent_handle;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
struct acpi_device *parent;
u64 adr;
/*
* For both sata/pata devices, host handle is required.
* For pata device, port handle is also required.
* For both sata/pata devices, host companion device is required.
* For pata device, port companion device is also required.
*/
if (libata_noacpi || !host_handle ||
(!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle))
if (libata_noacpi || !host_companion ||
(!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion))
return;
if (ap->flags & ATA_FLAG_ACPI_SATA) {
@ -216,13 +214,13 @@ void ata_acpi_bind_dev(struct ata_device *dev)
adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
else
adr = SATA_ADR(ap->port_no, dev->link->pmp);
parent_handle = host_handle;
parent = host_companion;
} else {
adr = dev->devno;
parent_handle = port_handle;
parent = port_companion;
}
acpi_preset_companion(&dev->tdev, parent_handle, adr);
acpi_preset_companion(&dev->tdev, parent, adr);
register_hotplug_dock_device(ata_dev_acpi_handle(dev),
&ata_acpi_dev_dock_ops, dev, NULL, NULL);

View File

@ -12,11 +12,10 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <acpi/acpi_bus.h>
#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/ata.h>
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_acpi"
#define DRV_VERSION "0.2.3"

View File

@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
topology.o
topology.o container.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/

View File

@ -100,6 +100,7 @@ static inline int hypervisor_init(void) { return 0; }
#endif
extern int platform_bus_init(void);
extern void cpu_dev_init(void);
extern void container_dev_init(void);
struct kobject *virtual_device_parent(struct device *dev);

44
drivers/base/container.c Normal file
View File

@ -0,0 +1,44 @@
/*
* System bus type for containers.
*
* Copyright (C) 2013, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/container.h>
#include "base.h"
#define CONTAINER_BUS_NAME "container"
static int trivial_online(struct device *dev)
{
return 0;
}
static int container_offline(struct device *dev)
{
struct container_dev *cdev = to_container_dev(dev);
return cdev->offline ? cdev->offline(cdev) : 0;
}
struct bus_type container_subsys = {
.name = CONTAINER_BUS_NAME,
.dev_name = CONTAINER_BUS_NAME,
.online = trivial_online,
.offline = container_offline,
};
void __init container_dev_init(void)
{
int ret;
ret = subsys_system_register(&container_subsys, NULL);
if (ret)
pr_err("%s() failed: %d\n", __func__, ret);
}

View File

@ -33,4 +33,5 @@ void __init driver_init(void)
platform_bus_init();
cpu_dev_init();
memory_dev_init();
container_dev_init();
}

View File

@ -677,7 +677,17 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
int len;
len = of_device_get_modalias(dev, buf, PAGE_SIZE -1);
if (len != -ENODEV)
return len;
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1);
if (len != -ENODEV)
return len;
len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
@ -699,6 +709,10 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
if (rc != -ENODEV)
return rc;
rc = acpi_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
pdev->name);
return 0;

View File

@ -32,6 +32,21 @@ struct pm_clock_entry {
enum pce_status status;
};
/**
* pm_clk_enable - Enable a clock, reporting any errors
* @dev: The device for the given clock
* @clk: The clock being enabled.
*/
static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
{
int ret = clk_enable(clk);
if (ret)
dev_err(dev, "%s: failed to enable clk %p, error %d\n",
__func__, clk, ret);
return ret;
}
/**
* pm_clk_acquire - Acquire a device clock.
* @dev: Device whose clock is to be acquired.
@ -43,6 +58,7 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
if (IS_ERR(ce->clk)) {
ce->status = PCE_STATUS_ERROR;
} else {
clk_prepare(ce->clk);
ce->status = PCE_STATUS_ACQUIRED;
dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
}
@ -99,10 +115,12 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
if (ce->status < PCE_STATUS_ERROR) {
if (ce->status == PCE_STATUS_ENABLED)
clk_disable_unprepare(ce->clk);
clk_disable(ce->clk);
if (ce->status >= PCE_STATUS_ACQUIRED)
if (ce->status >= PCE_STATUS_ACQUIRED) {
clk_unprepare(ce->clk);
clk_put(ce->clk);
}
}
kfree(ce->con_id);
@ -249,6 +267,7 @@ int pm_clk_resume(struct device *dev)
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
unsigned long flags;
int ret;
dev_dbg(dev, "%s()\n", __func__);
@ -259,8 +278,9 @@ int pm_clk_resume(struct device *dev)
list_for_each_entry(ce, &psd->clock_list, node) {
if (ce->status < PCE_STATUS_ERROR) {
clk_enable(ce->clk);
ce->status = PCE_STATUS_ENABLED;
ret = __pm_clk_enable(dev, ce->clk);
if (!ret)
ce->status = PCE_STATUS_ENABLED;
}
}
@ -376,7 +396,7 @@ int pm_clk_resume(struct device *dev)
spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry(ce, &psd->clock_list, node)
clk_enable(ce->clk);
__pm_clk_enable(dev, ce->clk);
spin_unlock_irqrestore(&psd->lock, flags);

View File

@ -10,7 +10,7 @@
#include <linux/pm_runtime.h>
#include <linux/export.h>
#ifdef CONFIG_PM_RUNTIME
#ifdef CONFIG_PM
/**
* pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
* @dev: Device to suspend.
@ -48,7 +48,7 @@ int pm_generic_runtime_resume(struct device *dev)
return ret;
}
EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
#endif /* CONFIG_PM_RUNTIME */
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
/**

Some files were not shown because too many files have changed in this diff Show More