summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig38
-rw-r--r--drivers/acpi/Makefile6
-rw-r--r--drivers/acpi/acpi_lpss.c98
-rw-r--r--drivers/acpi/acpi_platform.c3
-rw-r--r--drivers/acpi/acpica/acglobal.h1
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/aclocal.h8
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/amlresrc.h34
-rw-r--r--drivers/acpi/acpica/evgpe.c30
-rw-r--r--drivers/acpi/acpica/evgpeinit.c1
-rw-r--r--drivers/acpi/acpica/evxface.c27
-rw-r--r--drivers/acpi/acpica/evxfevnt.c40
-rw-r--r--drivers/acpi/acpica/evxfgpe.c12
-rw-r--r--drivers/acpi/acpica/hwgpe.c62
-rw-r--r--drivers/acpi/acpica/tbxfroot.c33
-rw-r--r--drivers/acpi/acpica/utresrc.c2
-rw-r--r--drivers/acpi/acpica/utxface.c4
-rw-r--r--drivers/acpi/acpica/utxfinit.c11
-rw-r--r--drivers/acpi/apei/ghes.c20
-rw-r--r--drivers/acpi/battery.c4
-rw-r--r--drivers/acpi/blacklist.c8
-rw-r--r--drivers/acpi/device_pm.c15
-rw-r--r--drivers/acpi/ec.c134
-rw-r--r--drivers/acpi/fan.c338
-rw-r--r--drivers/acpi/int340x_thermal.c51
-rw-r--r--drivers/acpi/internal.h16
-rw-r--r--drivers/acpi/osl.c8
-rw-r--r--drivers/acpi/pci_irq.c2
-rw-r--r--drivers/acpi/pci_root.c16
-rw-r--r--drivers/acpi/pmic/intel_pmic.c354
-rw-r--r--drivers/acpi/pmic/intel_pmic.h25
-rw-r--r--drivers/acpi/pmic/intel_pmic_crc.c211
-rw-r--r--drivers/acpi/pmic/intel_pmic_xpower.c268
-rw-r--r--drivers/acpi/processor_idle.c20
-rw-r--r--drivers/acpi/property.c551
-rw-r--r--drivers/acpi/scan.c287
-rw-r--r--drivers/acpi/sleep.c2
-rw-r--r--drivers/acpi/sysfs.c4
-rw-r--r--drivers/acpi/tables.c68
-rw-r--r--drivers/acpi/thermal.c18
-rw-r--r--drivers/acpi/utils.c33
-rw-r--r--drivers/acpi/video.c18
43 files changed, 2550 insertions, 335 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index d0f3265fb85d..8951cefb0a96 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -144,7 +144,7 @@ config ACPI_VIDEO
config ACPI_FAN
tristate "Fan"
- select THERMAL
+ depends on THERMAL
default y
help
This driver supports ACPI fan devices, allowing user-mode
@@ -360,15 +360,14 @@ config ACPI_BGRT
config ACPI_REDUCED_HARDWARE_ONLY
bool "Hardware-reduced ACPI support only" if EXPERT
def_bool n
- depends on ACPI
help
- This config item changes the way the ACPI code is built. When this
- option is selected, the kernel will use a specialized version of
- ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
- resulting kernel will be smaller but it will also be restricted to
- running in ACPI reduced hardware mode ONLY.
+ This config item changes the way the ACPI code is built. When this
+ option is selected, the kernel will use a specialized version of
+ ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
+ resulting kernel will be smaller but it will also be restricted to
+ running in ACPI reduced hardware mode ONLY.
- If you are unsure what to do, do not enable this option.
+ If you are unsure what to do, do not enable this option.
source "drivers/acpi/apei/Kconfig"
@@ -394,4 +393,27 @@ config ACPI_EXTLOG
driver adds support for that functionality with corresponding
tracepoint which carries that information to userspace.
+menuconfig PMIC_OPREGION
+ bool "PMIC (Power Management Integrated Circuit) operation region support"
+ help
+ Select this option to enable support for ACPI operation
+ region of the PMIC chip. The operation region can be used
+ to control power rails and sensor reading/writing on the
+ PMIC chip.
+
+if PMIC_OPREGION
+config CRC_PMIC_OPREGION
+ bool "ACPI operation region support for CrystalCove PMIC"
+ depends on INTEL_SOC_PMIC
+ help
+ This config adds ACPI operation region support for CrystalCove PMIC.
+
+config XPOWER_PMIC_OPREGION
+ bool "ACPI operation region support for XPower AXP288 PMIC"
+ depends on AXP288_ADC = y
+ help
+ This config adds ACPI operation region support for XPower AXP288 PMIC.
+
+endif
+
endif # ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 505d4d79fe3e..f74317cc1ca9 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -43,9 +43,11 @@ acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-y += acpi_lpss.o
acpi-y += acpi_platform.o
acpi-y += acpi_pnp.o
+acpi-y += int340x_thermal.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
@@ -86,3 +88,7 @@ obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
obj-$(CONFIG_ACPI_APEI) += apei/
obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o
+
+obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o
+obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
+obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 93d160661f4c..4f3febf8a589 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -1,7 +1,7 @@
/*
* ACPI support for Intel Lynxpoint LPSS.
*
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2014, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
@@ -60,6 +60,8 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_CLK_DIVIDER BIT(2)
#define LPSS_LTR BIT(3)
#define LPSS_SAVE_CTX BIT(4)
+#define LPSS_DEV_PROXY BIT(5)
+#define LPSS_PROXY_REQ BIT(6)
struct lpss_private_data;
@@ -70,8 +72,10 @@ struct lpss_device_desc {
void (*setup)(struct lpss_private_data *pdata);
};
+static struct device *proxy_device;
+
static struct lpss_device_desc lpss_dma_desc = {
- .flags = LPSS_CLK,
+ .flags = LPSS_CLK | LPSS_PROXY_REQ,
};
struct lpss_private_data {
@@ -146,22 +150,24 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
};
static struct lpss_device_desc byt_uart_dev_desc = {
- .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+ LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = lpss_uart_setup,
};
static struct lpss_device_desc byt_spi_dev_desc = {
- .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+ LPSS_DEV_PROXY,
.prv_offset = 0x400,
};
static struct lpss_device_desc byt_sdio_dev_desc = {
- .flags = LPSS_CLK,
+ .flags = LPSS_CLK | LPSS_DEV_PROXY,
};
static struct lpss_device_desc byt_i2c_dev_desc = {
- .flags = LPSS_CLK | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
};
@@ -368,6 +374,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev);
if (!IS_ERR_OR_NULL(pdev)) {
+ if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY)
+ proxy_device = &pdev->dev;
return 1;
}
@@ -499,14 +507,15 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
/**
* acpi_lpss_save_ctx() - Save the private registers of LPSS device
* @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
*
* Most LPSS devices have private registers which may loose their context when
* the device is powered down. acpi_lpss_save_ctx() saves those registers into
* prv_reg_ctx array.
*/
-static void acpi_lpss_save_ctx(struct device *dev)
+static void acpi_lpss_save_ctx(struct device *dev,
+ struct lpss_private_data *pdata)
{
- struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
@@ -521,12 +530,13 @@ static void acpi_lpss_save_ctx(struct device *dev)
/**
* acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
* @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
*
* Restores the registers that were previously stored with acpi_lpss_save_ctx().
*/
-static void acpi_lpss_restore_ctx(struct device *dev)
+static void acpi_lpss_restore_ctx(struct device *dev,
+ struct lpss_private_data *pdata)
{
- struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
/*
@@ -549,54 +559,82 @@ static void acpi_lpss_restore_ctx(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int acpi_lpss_suspend_late(struct device *dev)
{
- int ret = pm_generic_suspend_late(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = pm_generic_suspend_late(dev);
if (ret)
return ret;
- acpi_lpss_save_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_save_ctx(dev, pdata);
+
return acpi_dev_suspend_late(dev);
}
static int acpi_lpss_resume_early(struct device *dev)
{
- int ret = acpi_dev_resume_early(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = acpi_dev_resume_early(dev);
if (ret)
return ret;
- acpi_lpss_restore_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_restore_ctx(dev, pdata);
+
return pm_generic_resume_early(dev);
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
static int acpi_lpss_runtime_suspend(struct device *dev)
{
- int ret = pm_generic_runtime_suspend(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ ret = pm_generic_runtime_suspend(dev);
+ if (ret)
+ return ret;
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_save_ctx(dev, pdata);
+
+ ret = acpi_dev_runtime_suspend(dev);
if (ret)
return ret;
- acpi_lpss_save_ctx(dev);
- return acpi_dev_runtime_suspend(dev);
+ if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device)
+ return pm_runtime_put_sync_suspend(proxy_device);
+
+ return 0;
}
static int acpi_lpss_runtime_resume(struct device *dev)
{
- int ret = acpi_dev_runtime_resume(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) {
+ ret = pm_runtime_get_sync(proxy_device);
+ if (ret)
+ return ret;
+ }
+ ret = acpi_dev_runtime_resume(dev);
if (ret)
return ret;
- acpi_lpss_restore_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_restore_ctx(dev, pdata);
+
return pm_generic_runtime_resume(dev);
}
-#endif /* CONFIG_PM_RUNTIME */
#endif /* CONFIG_PM */
static struct dev_pm_domain acpi_lpss_pm_domain = {
.ops = {
+#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
@@ -608,7 +646,6 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
.poweroff_late = acpi_lpss_suspend_late,
.restore_early = acpi_lpss_resume_early,
#endif
-#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = acpi_lpss_runtime_suspend,
.runtime_resume = acpi_lpss_runtime_resume,
#endif
@@ -631,30 +668,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
return 0;
pdata = acpi_driver_data(adev);
- if (!pdata || !pdata->mmio_base)
+ if (!pdata)
return 0;
- if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
+ if (pdata->mmio_base &&
+ pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
return 0;
}
switch (action) {
- case BUS_NOTIFY_BOUND_DRIVER:
- if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
- pdev->dev.pm_domain = &acpi_lpss_pm_domain;
- break;
- case BUS_NOTIFY_UNBOUND_DRIVER:
- if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
- pdev->dev.pm_domain = NULL;
- break;
case BUS_NOTIFY_ADD_DEVICE:
+ pdev->dev.pm_domain = &acpi_lpss_pm_domain;
if (pdata->dev_desc->flags & LPSS_LTR)
return sysfs_create_group(&pdev->dev.kobj,
&lpss_attr_group);
+ break;
case BUS_NOTIFY_DEL_DEVICE:
if (pdata->dev_desc->flags & LPSS_LTR)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+ pdev->dev.pm_domain = NULL;
+ break;
default:
break;
}
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 2bf9082f7523..6ba8beb6b9d2 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include "internal.h"
@@ -102,6 +103,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
pdevinfo.res = resources;
pdevinfo.num_res = count;
pdevinfo.acpi_node.companion = adev;
+ pdevinfo.dma_mask = DMA_BIT_MASK(32);
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev))
dev_err(&adev->dev, "platform device creation failed: %ld\n",
@@ -113,3 +115,4 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
kfree(resources);
return pdev;
}
+EXPORT_SYMBOL_GPL(acpi_create_platform_device);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index ebf02cc10a43..7f60582d0c8c 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -305,6 +305,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_db_output_flags, ACPI_DB_CONSOLE_OUTPUT);
ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 2ad2351a9833..c318d3e27893 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -127,7 +127,7 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
acpi_status
acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
- acpi_event_status * event_status);
+ acpi_event_status *event_status);
acpi_status acpi_hw_disable_all_gpes(void);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 2747279fbe3c..680d23bbae7c 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -413,8 +413,8 @@ struct acpi_gpe_handler_info {
acpi_gpe_handler address; /* Address of handler, if any */
void *context; /* Context to be passed to handler */
struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */
- u8 original_flags; /* Original (pre-handler) GPE info */
- u8 originally_enabled; /* True if GPE was originally enabled */
+ u8 original_flags; /* Original (pre-handler) GPE info */
+ u8 originally_enabled; /* True if GPE was originally enabled */
};
/* Notify info for implicit notify, multiple device objects */
@@ -454,6 +454,7 @@ struct acpi_gpe_register_info {
u16 base_gpe_number; /* Base GPE number for this register */
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
u8 enable_for_run; /* GPEs to keep enabled when running */
+ u8 enable_mask; /* Current mask of enabled GPEs */
};
/*
@@ -722,6 +723,7 @@ union acpi_parse_value {
ACPI_DISASM_ONLY_MEMBERS (\
u8 disasm_flags; /* Used during AML disassembly */\
u8 disasm_opcode; /* Subtype used for disassembly */\
+ char *operator_symbol;/* Used for C-style operator name strings */\
char aml_op_name[16]) /* Op name (debug only) */
/* Flags for disasm_flags field above */
@@ -827,6 +829,8 @@ struct acpi_parse_state {
#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04
#define ACPI_PARSEOP_PREDEF_CHECKED 0x08
#define ACPI_PARSEOP_SPECIAL 0x10
+#define ACPI_PARSEOP_COMPOUND 0x20
+#define ACPI_PARSEOP_ASSIGNMENT 0x40
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index f14882788eee..1afe46e44dac 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -49,6 +49,8 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count);
/*
* tbxfroot - Root pointer utilities
*/
+u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp);
+
acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index f3f834408441..3a0beeb86ba5 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -117,6 +117,12 @@ struct asl_resource_node {
struct asl_resource_node *next;
};
+struct asl_resource_info {
+ union acpi_parse_object *descriptor_type_op; /* Resource descriptor parse node */
+ union acpi_parse_object *mapping_op; /* Used for mapfile support */
+ u32 current_byte_offset; /* Offset in resource template */
+};
+
/* Macros used to generate AML resource length fields */
#define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (struct aml_resource_large_header))
@@ -449,4 +455,32 @@ union aml_resource {
u8 byte_item;
};
+/* Interfaces used by both the disassembler and compiler */
+
+void
+mp_save_gpio_info(union acpi_parse_object *op,
+ union aml_resource *resource,
+ u32 pin_count, u16 *pin_list, char *device_name);
+
+void
+mp_save_serial_info(union acpi_parse_object *op,
+ union aml_resource *resource, char *device_name);
+
+char *mp_get_hid_from_parse_tree(struct acpi_namespace_node *hid_node);
+
+char *mp_get_hid_via_namestring(char *device_name);
+
+char *mp_get_connection_info(union acpi_parse_object *op,
+ u32 pin_index,
+ struct acpi_namespace_node **target_node,
+ char **target_name);
+
+char *mp_get_parent_device_hid(union acpi_parse_object *op,
+ struct acpi_namespace_node **target_node,
+ char **parent_device_name);
+
+char *mp_get_ddn_value(char *device_name);
+
+char *mp_get_hid_value(struct acpi_namespace_node *device_node);
+
#endif
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index e4ba4dec86af..aa70154cf4fa 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -100,13 +100,14 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
*
* FUNCTION: acpi_ev_enable_gpe
*
- * PARAMETERS: gpe_event_info - GPE to enable
+ * PARAMETERS: gpe_event_info - GPE to enable
*
* RETURN: Status
*
* DESCRIPTION: Clear a GPE of stale events and enable it.
*
******************************************************************************/
+
acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status;
@@ -125,6 +126,7 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
}
/* Clear the GPE (of stale events) */
+
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -132,11 +134,10 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Enable the requested GPE */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE_SAVE);
return_ACPI_STATUS(status);
}
-
/*******************************************************************************
*
* FUNCTION: acpi_ev_add_gpe_reference
@@ -212,7 +213,7 @@ acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
if (ACPI_SUCCESS(status)) {
status =
acpi_hw_low_set_gpe(gpe_event_info,
- ACPI_GPE_DISABLE);
+ ACPI_GPE_DISABLE_SAVE);
}
if (ACPI_FAILURE(status)) {
@@ -334,7 +335,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
*
******************************************************************************/
-u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
+u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
{
acpi_status status;
struct acpi_gpe_block_info *gpe_block;
@@ -427,7 +428,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Check if there is anything active at all in this register */
- enabled_status_byte = (u8) (status_reg & enable_reg);
+ enabled_status_byte = (u8)(status_reg & enable_reg);
if (!enabled_status_byte) {
/* No active GPEs in this register, move on */
@@ -450,7 +451,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
acpi_ev_gpe_dispatch(gpe_block->
node,
&gpe_block->
- event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
+ event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
}
}
}
@@ -615,8 +616,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
+ acpi_cpu_flags flags;
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
(void)acpi_ev_finish_gpe(gpe_event_info);
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
ACPI_FREE(gpe_event_info);
return;
@@ -636,7 +640,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
*
******************************************************************************/
-acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
{
acpi_status status;
@@ -654,7 +658,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
/*
* Enable this GPE, conditionally. This means that the GPE will
- * only be physically enabled if the enable_for_run bit is set
+ * only be physically enabled if the enable_mask bit is set
* in the event_info.
*/
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
@@ -666,9 +670,9 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
*
* FUNCTION: acpi_ev_gpe_dispatch
*
- * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
- * gpe_event_info - Info for this GPE
- * gpe_number - Number relative to the parent GPE block
+ * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
+ * gpe_event_info - Info for this GPE
+ * gpe_number - Number relative to the parent GPE block
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
@@ -681,7 +685,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
u32
acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
- struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+ struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
acpi_status status;
u32 return_value;
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 49fc7effd961..7be928379879 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -424,6 +424,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
}
/* Disable the GPE in case it's been enabled already. */
+
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
/*
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 11e5803b8b41..55a58f3ec8df 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -786,18 +786,26 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
handler->method_node = gpe_event_info->dispatch.method_node;
handler->original_flags = (u8)(gpe_event_info->flags &
(ACPI_GPE_XRUPT_TYPE_MASK |
- ACPI_GPE_DISPATCH_MASK));
+ ACPI_GPE_DISPATCH_MASK));
/*
* If the GPE is associated with a method, it may have been enabled
* automatically during initialization, in which case it has to be
* disabled now to avoid spurious execution of the handler.
*/
-
- if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
- && gpe_event_info->runtime_count) {
- handler->originally_enabled = 1;
+ if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
+ (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
+ gpe_event_info->runtime_count) {
+ handler->originally_enabled = TRUE;
(void)acpi_ev_remove_gpe_reference(gpe_event_info);
+
+ /* Sanity check of original type against new type */
+
+ if (type !=
+ (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
+ ACPI_WARNING((AE_INFO,
+ "GPE type mismatch (level/edge)"));
+ }
}
/* Install the handler */
@@ -808,7 +816,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
- gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
+ gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER);
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
@@ -893,7 +901,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
gpe_event_info->dispatch.method_node = handler->method_node;
gpe_event_info->flags &=
- ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+ ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
gpe_event_info->flags |= handler->original_flags;
/*
@@ -901,7 +909,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
* enabled, it should be enabled at this point to restore the
* post-initialization configuration.
*/
- if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) &&
+ if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
+ (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
handler->originally_enabled) {
(void)acpi_ev_add_gpe_reference(gpe_event_info);
}
@@ -946,7 +955,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
* handle is returned.
*
******************************************************************************/
-acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
+acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle)
{
acpi_status status;
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index e286640ad4ff..bb8cbf5961bf 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -324,8 +324,9 @@ ACPI_EXPORT_SYMBOL(acpi_clear_event)
******************************************************************************/
acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
{
- acpi_status status = AE_OK;
- u32 value;
+ acpi_status status;
+ acpi_event_status local_event_status = 0;
+ u32 in_byte;
ACPI_FUNCTION_TRACE(acpi_get_event_status);
@@ -339,29 +340,40 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the status of the requested fixed event */
+ /* Fixed event currently can be dispatched? */
+
+ if (acpi_gbl_fixed_event_handlers[event].handler) {
+ local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER;
+ }
+
+ /* Fixed event currently enabled? */
status =
acpi_read_bit_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value);
- if (ACPI_FAILURE(status))
+ enable_register_id, &in_byte);
+ if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
+ }
- *event_status = value;
+ if (in_byte) {
+ local_event_status |= ACPI_EVENT_FLAG_ENABLED;
+ }
+
+ /* Fixed event currently active? */
status =
acpi_read_bit_register(acpi_gbl_fixed_event_info[event].
- status_register_id, &value);
- if (ACPI_FAILURE(status))
+ status_register_id, &in_byte);
+ if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
+ }
- if (value)
- *event_status |= ACPI_EVENT_FLAG_SET;
-
- if (acpi_gbl_fixed_event_handlers[event].handler)
- *event_status |= ACPI_EVENT_FLAG_HANDLE;
+ if (in_byte) {
+ local_event_status |= ACPI_EVENT_FLAG_SET;
+ }
- return_ACPI_STATUS(status);
+ (*event_status) = local_event_status;
+ return_ACPI_STATUS(AE_OK);
}
ACPI_EXPORT_SYMBOL(acpi_get_event_status)
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 56710a03c9b0..e889a5304abd 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -106,8 +106,8 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
*
* FUNCTION: acpi_enable_gpe
*
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
*
* RETURN: Status
*
@@ -115,7 +115,6 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
* hardware-enabled.
*
******************************************************************************/
-
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
{
acpi_status status = AE_BAD_PARAMETER;
@@ -490,8 +489,8 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
*
* FUNCTION: acpi_get_gpe_status
*
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
* event_status - Where the current status of the event
* will be returned
*
@@ -524,9 +523,6 @@ acpi_get_gpe_status(acpi_handle gpe_device,
status = acpi_hw_get_gpe_status(gpe_event_info, event_status);
- if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
- *event_status |= ACPI_EVENT_FLAG_HANDLE;
-
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index ea62d40fd161..494027f5c067 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -115,12 +115,12 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/* Set or clear just the bit that corresponds to this GPE */
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
- switch (action) {
+ switch (action & ~ACPI_GPE_SAVE_MASK) {
case ACPI_GPE_CONDITIONAL_ENABLE:
- /* Only enable if the enable_for_run bit is set */
+ /* Only enable if the corresponding enable_mask bit is set */
- if (!(register_bit & gpe_register_info->enable_for_run)) {
+ if (!(register_bit & gpe_register_info->enable_mask)) {
return (AE_BAD_PARAMETER);
}
@@ -145,6 +145,9 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/* Write the updated enable mask */
status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+ if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) {
+ gpe_register_info->enable_mask = enable_mask;
+ }
return (status);
}
@@ -202,7 +205,7 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
acpi_status
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
- acpi_event_status * event_status)
+ acpi_event_status *event_status)
{
u32 in_byte;
u32 register_bit;
@@ -216,6 +219,13 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
return (AE_BAD_PARAMETER);
}
+ /* GPE currently handled? */
+
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
+ ACPI_GPE_DISPATCH_NONE) {
+ local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER;
+ }
+
/* Get the info block for the entire GPE register */
gpe_register_info = gpe_event_info->register_info;
@@ -255,6 +265,32 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/******************************************************************************
*
+ * FUNCTION: acpi_hw_gpe_enable_write
+ *
+ * PARAMETERS: enable_mask - Bit mask to write to the GPE register
+ * gpe_register_info - Gpe Register info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write the enable mask byte to the given GPE register.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_gpe_enable_write(u8 enable_mask,
+ struct acpi_gpe_register_info *gpe_register_info)
+{
+ acpi_status status;
+
+ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+ if (ACPI_SUCCESS(status)) {
+ gpe_register_info->enable_mask = enable_mask;
+ }
+ return (status);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_hw_disable_gpe_block
*
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info
@@ -280,8 +316,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Disable all GPEs in this register */
status =
- acpi_hw_write(0x00,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(0x00,
+ &gpe_block->register_info[i]);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -348,21 +384,23 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
{
u32 i;
acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
/* NOTE: assumes that all GPEs are currently disabled */
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
- if (!gpe_block->register_info[i].enable_for_run) {
+ gpe_register_info = &gpe_block->register_info[i];
+ if (!gpe_register_info->enable_for_run) {
continue;
}
/* Enable all "runtime" GPEs in this register */
status =
- acpi_hw_write(gpe_block->register_info[i].enable_for_run,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run,
+ gpe_register_info);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -392,10 +430,12 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
{
u32 i;
acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
+ gpe_register_info = &gpe_block->register_info[i];
/*
* Enable all "wake" GPEs in this register and disable the
@@ -403,8 +443,8 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
*/
status =
- acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake,
+ gpe_register_info);
if (ACPI_FAILURE(status)) {
return (status);
}
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 65ab8fed3d5e..43a54af2b548 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -50,6 +50,36 @@ ACPI_MODULE_NAME("tbxfroot")
/*******************************************************************************
*
+ * FUNCTION: acpi_tb_get_rsdp_length
+ *
+ * PARAMETERS: rsdp - Pointer to RSDP
+ *
+ * RETURN: Table length
+ *
+ * DESCRIPTION: Get the length of the RSDP
+ *
+ ******************************************************************************/
+u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp)
+{
+
+ if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) {
+
+ /* BAD Signature */
+
+ return (0);
+ }
+
+ /* "Length" field is available if table version >= 2 */
+
+ if (rsdp->revision >= 2) {
+ return (rsdp->length);
+ } else {
+ return (ACPI_RSDP_CHECKSUM_LENGTH);
+ }
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_tb_validate_rsdp
*
* PARAMETERS: rsdp - Pointer to unvalidated RSDP
@@ -59,7 +89,8 @@ ACPI_MODULE_NAME("tbxfroot")
* DESCRIPTION: Validate the RSDP (ptr)
*
******************************************************************************/
-acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
+
+acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp * rsdp)
{
/*
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 5cd017c7ac0e..bc1ff820c7dd 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -263,7 +263,7 @@ const char *acpi_gbl_bpb_decode[] = {
/* UART serial bus stop bits */
const char *acpi_gbl_sb_decode[] = {
- "StopBitsNone",
+ "StopBitsZero",
"StopBitsOne",
"StopBitsOnePlusHalf",
"StopBitsTwo"
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 502a8492dc83..49c873c68756 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -531,7 +531,9 @@ acpi_decode_pld_buffer(u8 *in_buffer,
ACPI_MOVE_32_TO_32(&dword, &buffer[0]);
pld_info->revision = ACPI_PLD_GET_REVISION(&dword);
pld_info->ignore_color = ACPI_PLD_GET_IGNORE_COLOR(&dword);
- pld_info->color = ACPI_PLD_GET_COLOR(&dword);
+ pld_info->red = ACPI_PLD_GET_RED(&dword);
+ pld_info->green = ACPI_PLD_GET_GREEN(&dword);
+ pld_info->blue = ACPI_PLD_GET_BLUE(&dword);
/* Second 32-bit DWord */
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 13380d818462..b1fd6886e439 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -53,6 +53,9 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxfinit")
+/* For acpi_exec only */
+void ae_do_object_overrides(void);
+
/*******************************************************************************
*
* FUNCTION: acpi_initialize_subsystem
@@ -65,6 +68,7 @@ ACPI_MODULE_NAME("utxfinit")
* called, so any early initialization belongs here.
*
******************************************************************************/
+
acpi_status __init acpi_initialize_subsystem(void)
{
acpi_status status;
@@ -275,6 +279,13 @@ acpi_status __init acpi_initialize_objects(u32 flags)
return_ACPI_STATUS(status);
}
}
+#ifdef ACPI_EXEC_APP
+ /*
+ * This call implements the "initialization file" option for acpi_exec.
+ * This is the precise point that we want to perform the overrides.
+ */
+ ae_do_object_overrides();
+#endif
/*
* Execute any module-level code that was detected during the table load
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index fc5f780bb61d..1b6aa514848f 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -128,7 +128,7 @@ static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
static struct gen_pool *ghes_estatus_pool;
static unsigned long ghes_estatus_pool_size_request;
-struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
+static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
static atomic_t ghes_estatus_cache_alloced;
static int ghes_ioremap_init(void)
@@ -738,20 +738,6 @@ static LIST_HEAD(ghes_nmi);
static int ghes_panic_timeout __read_mostly = 30;
-static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
-{
- struct llist_node *next, *tail = NULL;
-
- while (llnode) {
- next = llnode->next;
- llnode->next = tail;
- tail = llnode;
- llnode = next;
- }
-
- return tail;
-}
-
static void ghes_proc_in_irq(struct irq_work *irq_work)
{
struct llist_node *llnode, *next;
@@ -765,7 +751,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
* Because the time order of estatus in list is reversed,
* revert it back to proper order.
*/
- llnode = llist_nodes_reverse(llnode);
+ llnode = llist_reverse_order(llnode);
while (llnode) {
next = llnode->next;
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
@@ -798,7 +784,7 @@ static void ghes_print_queued_estatus(void)
* Because the time order of estatus in list is reversed,
* revert it back to proper order.
*/
- llnode = llist_nodes_reverse(llnode);
+ llnode = llist_reverse_order(llnode);
while (llnode) {
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
llnode);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 8ec8a89a20ab..d98ba4355819 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1180,6 +1180,10 @@ static int acpi_battery_add(struct acpi_device *device)
if (!device)
return -EINVAL;
+
+ if (device->dep_unmet)
+ return -EPROBE_DEFER;
+
battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
return -ENOMEM;
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index ed122e17636e..7556e7c4a055 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -290,6 +290,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3446"),
},
},
+ {
+ .callback = dmi_disable_osi_win8,
+ .ident = "Dell Vostro 3546",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3546"),
+ },
+ },
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index bea6896be122..897640188acd 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -201,7 +201,7 @@ int acpi_device_set_power(struct acpi_device *device, int state)
* Transition Power
* ----------------
* In accordance with the ACPI specification first apply power (via
- * power resources) and then evalute _PSx.
+ * power resources) and then evaluate _PSx.
*/
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
@@ -343,6 +343,7 @@ int acpi_device_update_power(struct acpi_device *device, int *state_p)
return 0;
}
+EXPORT_SYMBOL_GPL(acpi_device_update_power);
int acpi_bus_update_power(acpi_handle handle, int *state_p)
{
@@ -691,7 +692,6 @@ static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
/**
* acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable the platform to wake up.
@@ -710,10 +710,9 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
return -ENODEV;
}
- return acpi_device_wakeup(adev, enable, ACPI_STATE_S0);
+ return acpi_device_wakeup(adev, ACPI_STATE_S0, enable);
}
EXPORT_SYMBOL(acpi_pm_device_run_wake);
-#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
/**
@@ -772,7 +771,6 @@ static int acpi_dev_pm_full_power(struct acpi_device *adev)
acpi_device_set_power(adev, ACPI_STATE_D0) : 0;
}
-#ifdef CONFIG_PM_RUNTIME
/**
* acpi_dev_runtime_suspend - Put device into a low-power state using ACPI.
* @dev: Device to put into a low-power state.
@@ -854,7 +852,6 @@ int acpi_subsys_runtime_resume(struct device *dev)
return ret ? ret : pm_generic_runtime_resume(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
-#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
/**
@@ -877,7 +874,7 @@ int acpi_dev_suspend_late(struct device *dev)
return 0;
target_state = acpi_target_system_state();
- wakeup = device_may_wakeup(dev);
+ wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
error = acpi_device_wakeup(adev, target_state, wakeup);
if (wakeup && error)
return error;
@@ -1022,10 +1019,9 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
static struct dev_pm_domain acpi_general_pm_domain = {
.ops = {
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
.runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume,
-#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
@@ -1037,6 +1033,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
.poweroff_late = acpi_subsys_suspend_late,
.restore_early = acpi_subsys_resume_early,
#endif
+#endif
},
};
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index cb6066c809ea..5f9b74b9b71f 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -126,14 +126,16 @@ static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
+static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
/* --------------------------------------------------------------------------
- Transaction Management
- -------------------------------------------------------------------------- */
+ * Transaction Management
+ * -------------------------------------------------------------------------- */
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
{
u8 x = inb(ec->command_addr);
+
pr_debug("EC_SC(R) = 0x%2.2x "
"SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n",
x,
@@ -148,6 +150,7 @@ static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
u8 x = inb(ec->data_addr);
+
pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
return x;
}
@@ -164,10 +167,32 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb(data, ec->data_addr);
}
+#ifdef DEBUG
+static const char *acpi_ec_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ case 0x80:
+ return "RD_EC";
+ case 0x81:
+ return "WR_EC";
+ case 0x82:
+ return "BE_EC";
+ case 0x83:
+ return "BD_EC";
+ case 0x84:
+ return "QR_EC";
+ }
+ return "UNKNOWN";
+}
+#else
+#define acpi_ec_cmd_string(cmd) "UNDEF"
+#endif
+
static int ec_transaction_completed(struct acpi_ec *ec)
{
unsigned long flags;
int ret = 0;
+
spin_lock_irqsave(&ec->lock, flags);
if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
ret = 1;
@@ -181,7 +206,8 @@ static bool advance_transaction(struct acpi_ec *ec)
u8 status;
bool wakeup = false;
- pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK");
+ pr_debug("===== %s (%d) =====\n",
+ in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
status = acpi_ec_read_status(ec);
t = ec->curr;
if (!t)
@@ -198,7 +224,8 @@ static bool advance_transaction(struct acpi_ec *ec)
if (t->rlen == t->ri) {
t->flags |= ACPI_EC_COMMAND_COMPLETE;
if (t->command == ACPI_EC_COMMAND_QUERY)
- pr_debug("hardware QR_EC completion\n");
+ pr_debug("***** Command(%s) hardware completion *****\n",
+ acpi_ec_cmd_string(t->command));
wakeup = true;
}
} else
@@ -210,18 +237,14 @@ static bool advance_transaction(struct acpi_ec *ec)
}
return wakeup;
} else {
- /*
- * There is firmware refusing to respond QR_EC when SCI_EVT
- * is not set, for which case, we complete the QR_EC
- * without issuing it to the firmware.
- * https://bugzilla.kernel.org/show_bug.cgi?id=86211
- */
- if (!(status & ACPI_EC_FLAG_SCI) &&
+ if (EC_FLAGS_QUERY_HANDSHAKE &&
+ !(status & ACPI_EC_FLAG_SCI) &&
(t->command == ACPI_EC_COMMAND_QUERY)) {
t->flags |= ACPI_EC_COMMAND_POLL;
t->rdata[t->ri++] = 0x00;
t->flags |= ACPI_EC_COMMAND_COMPLETE;
- pr_debug("software QR_EC completion\n");
+ pr_debug("***** Command(%s) software completion *****\n",
+ acpi_ec_cmd_string(t->command));
wakeup = true;
} else if ((status & ACPI_EC_FLAG_IBF) == 0) {
acpi_ec_write_cmd(ec, t->command);
@@ -264,6 +287,7 @@ static int ec_poll(struct acpi_ec *ec)
{
unsigned long flags;
int repeat = 5; /* number of command restarts */
+
while (repeat--) {
unsigned long delay = jiffies +
msecs_to_jiffies(ec_delay);
@@ -296,18 +320,25 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
{
unsigned long tmp;
int ret = 0;
+
if (EC_FLAGS_MSI)
udelay(ACPI_EC_MSI_UDELAY);
/* start transaction */
spin_lock_irqsave(&ec->lock, tmp);
/* following two actions should be kept atomic */
ec->curr = t;
+ pr_debug("***** Command(%s) started *****\n",
+ acpi_ec_cmd_string(t->command));
start_transaction(ec);
+ if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ pr_debug("***** Event stopped *****\n");
+ }
spin_unlock_irqrestore(&ec->lock, tmp);
ret = ec_poll(ec);
spin_lock_irqsave(&ec->lock, tmp);
- if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
- clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ pr_debug("***** Command(%s) stopped *****\n",
+ acpi_ec_cmd_string(t->command));
ec->curr = NULL;
spin_unlock_irqrestore(&ec->lock, tmp);
return ret;
@@ -317,6 +348,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
{
int status;
u32 glk;
+
if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
return -EINVAL;
if (t->rdata)
@@ -333,8 +365,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
goto unlock;
}
}
- pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n",
- t->command, t->wdata ? t->wdata[0] : 0);
/* disable GPE during transaction if storm is detected */
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
/* It has to be disabled, so that it doesn't trigger. */
@@ -355,7 +385,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
t->irq_count);
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
}
- pr_debug("transaction end\n");
if (ec->global_lock)
acpi_release_global_lock(glk);
unlock:
@@ -383,7 +412,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
acpi_ec_transaction(ec, &t) : 0;
}
-static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
{
int result;
u8 d;
@@ -419,10 +448,9 @@ int ec_read(u8 addr, u8 *val)
if (!err) {
*val = temp_data;
return 0;
- } else
- return err;
+ }
+ return err;
}
-
EXPORT_SYMBOL(ec_read);
int ec_write(u8 addr, u8 val)
@@ -436,22 +464,21 @@ int ec_write(u8 addr, u8 val)
return err;
}
-
EXPORT_SYMBOL(ec_write);
int ec_transaction(u8 command,
- const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len)
+ const u8 *wdata, unsigned wdata_len,
+ u8 *rdata, unsigned rdata_len)
{
struct transaction t = {.command = command,
.wdata = wdata, .rdata = rdata,
.wlen = wdata_len, .rlen = rdata_len};
+
if (!first_ec)
return -ENODEV;
return acpi_ec_transaction(first_ec, &t);
}
-
EXPORT_SYMBOL(ec_transaction);
/* Get the handle to the EC device */
@@ -461,7 +488,6 @@ acpi_handle ec_get_handle(void)
return NULL;
return first_ec->handle;
}
-
EXPORT_SYMBOL(ec_get_handle);
/*
@@ -525,13 +551,14 @@ void acpi_ec_unblock_transactions_early(void)
clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
}
-static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data)
{
int result;
u8 d;
struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
.wdata = NULL, .rdata = &d,
.wlen = 0, .rlen = 1};
+
if (!ec || !data)
return -EINVAL;
/*
@@ -557,6 +584,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
{
struct acpi_ec_query_handler *handler =
kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+
if (!handler)
return -ENOMEM;
@@ -569,12 +597,12 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
mutex_unlock(&ec->mutex);
return 0;
}
-
EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
{
struct acpi_ec_query_handler *handler, *tmp;
+
mutex_lock(&ec->mutex);
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
if (query_bit == handler->query_bit) {
@@ -584,20 +612,20 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
}
mutex_unlock(&ec->mutex);
}
-
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
static void acpi_ec_run(void *cxt)
{
struct acpi_ec_query_handler *handler = cxt;
+
if (!handler)
return;
- pr_debug("start query execution\n");
+ pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit);
if (handler->func)
handler->func(handler->data);
else if (handler->handle)
acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
- pr_debug("stop query execution\n");
+ pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
kfree(handler);
}
@@ -620,8 +648,8 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
if (!copy)
return -ENOMEM;
memcpy(copy, handler, sizeof(*copy));
- pr_debug("push query execution (0x%2x) on queue\n",
- value);
+ pr_debug("##### Query(0x%02x) scheduled #####\n",
+ handler->query_bit);
return acpi_os_execute((copy->func) ?
OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
acpi_ec_run, copy);
@@ -633,6 +661,7 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
static void acpi_ec_gpe_query(void *ec_cxt)
{
struct acpi_ec *ec = ec_cxt;
+
if (!ec)
return;
mutex_lock(&ec->mutex);
@@ -644,7 +673,7 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
{
if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
- pr_debug("push gpe query to the queue\n");
+ pr_debug("***** Event started *****\n");
return acpi_os_execute(OSL_NOTIFY_HANDLER,
acpi_ec_gpe_query, ec);
}
@@ -667,8 +696,8 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
}
/* --------------------------------------------------------------------------
- Address Space Management
- -------------------------------------------------------------------------- */
+ * Address Space Management
+ * -------------------------------------------------------------------------- */
static acpi_status
acpi_ec_space_handler(u32 function, acpi_physical_address address,
@@ -699,27 +728,26 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
- break;
case -ENODEV:
return AE_NOT_FOUND;
- break;
case -ETIME:
return AE_TIME;
- break;
default:
return AE_OK;
}
}
/* --------------------------------------------------------------------------
- Driver Interface
- -------------------------------------------------------------------------- */
+ * Driver Interface
+ * -------------------------------------------------------------------------- */
+
static acpi_status
ec_parse_io_ports(struct acpi_resource *resource, void *context);
static struct acpi_ec *make_acpi_ec(void)
{
struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+
if (!ec)
return NULL;
ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
@@ -742,9 +770,8 @@ acpi_ec_register_query_methods(acpi_handle handle, u32 level,
status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
- if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) {
+ if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1)
acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
- }
return AE_OK;
}
@@ -753,7 +780,6 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
{
acpi_status status;
unsigned long long tmp = 0;
-
struct acpi_ec *ec = context;
/* clear addr values, ec_parse_io_ports depend on it */
@@ -781,6 +807,7 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
static int ec_install_handlers(struct acpi_ec *ec)
{
acpi_status status;
+
if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
return 0;
status = acpi_install_gpe_handler(NULL, ec->gpe,
@@ -981,6 +1008,18 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
}
/*
+ * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
+ * which case, we complete the QR_EC without issuing it to the firmware.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=86211
+ */
+static int ec_flag_query_handshake(const struct dmi_system_id *id)
+{
+ pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
+ EC_FLAGS_QUERY_HANDSHAKE = 1;
+ return 0;
+}
+
+/*
* On some hardware it is necessary to clear events accumulated by the EC during
* sleep. These ECs stop reporting GPEs until they are manually polled, if too
* many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
@@ -1054,6 +1093,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_clear_on_resume, "Samsung hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
+ {
+ ec_flag_query_handshake, "Acer hardware", {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
{},
};
@@ -1078,7 +1120,8 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
- acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
+ acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id,
+ &boot_ec->handle);
/* Don't trust ECDT, which comes from ASUSTek */
if (!EC_FLAGS_VALIDATE_ECDT)
goto install;
@@ -1162,6 +1205,5 @@ static void __exit acpi_ec_exit(void)
{
acpi_bus_unregister_driver(&acpi_ec_driver);
- return;
}
#endif /* 0 */
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 5328b1090e08..caf9b76b7ef8 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -30,22 +30,19 @@
#include <linux/uaccess.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
-
-#define ACPI_FAN_CLASS "fan"
-#define ACPI_FAN_FILE_STATE "state"
-
-#define _COMPONENT ACPI_FAN_COMPONENT
-ACPI_MODULE_NAME("fan");
+#include <linux/platform_device.h>
+#include <linux/sort.h>
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Fan Driver");
MODULE_LICENSE("GPL");
-static int acpi_fan_add(struct acpi_device *device);
-static int acpi_fan_remove(struct acpi_device *device);
+static int acpi_fan_probe(struct platform_device *pdev);
+static int acpi_fan_remove(struct platform_device *pdev);
static const struct acpi_device_id fan_device_ids[] = {
{"PNP0C0B", 0},
+ {"INT3404", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, fan_device_ids);
@@ -64,37 +61,100 @@ static struct dev_pm_ops acpi_fan_pm = {
#define FAN_PM_OPS_PTR NULL
#endif
-static struct acpi_driver acpi_fan_driver = {
- .name = "fan",
- .class = ACPI_FAN_CLASS,
- .ids = fan_device_ids,
- .ops = {
- .add = acpi_fan_add,
- .remove = acpi_fan_remove,
- },
- .drv.pm = FAN_PM_OPS_PTR,
+struct acpi_fan_fps {
+ u64 control;
+ u64 trip_point;
+ u64 speed;
+ u64 noise_level;
+ u64 power;
+};
+
+struct acpi_fan_fif {
+ u64 revision;
+ u64 fine_grain_ctrl;
+ u64 step_size;
+ u64 low_speed_notification;
+};
+
+struct acpi_fan {
+ bool acpi4;
+ struct acpi_fan_fif fif;
+ struct acpi_fan_fps *fps;
+ int fps_count;
+ struct thermal_cooling_device *cdev;
+};
+
+static struct platform_driver acpi_fan_driver = {
+ .probe = acpi_fan_probe,
+ .remove = acpi_fan_remove,
+ .driver = {
+ .name = "acpi-fan",
+ .acpi_match_table = fan_device_ids,
+ .pm = FAN_PM_OPS_PTR,
+ },
};
/* thermal cooling device callbacks */
static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
*state)
{
- /* ACPI fan device only support two states: ON/OFF */
- *state = 1;
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_fan *fan = acpi_driver_data(device);
+
+ if (fan->acpi4)
+ *state = fan->fps_count - 1;
+ else
+ *state = 1;
return 0;
}
-static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
- *state)
+static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_fan *fan = acpi_driver_data(device);
+ union acpi_object *obj;
+ acpi_status status;
+ int control, i;
+
+ status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&device->dev, "Get fan state failed\n");
+ return status;
+ }
+
+ obj = buffer.pointer;
+ if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
+ obj->package.count != 3 ||
+ obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
+ dev_err(&device->dev, "Invalid _FST data\n");
+ status = -EINVAL;
+ goto err;
+ }
+
+ control = obj->package.elements[1].integer.value;
+ for (i = 0; i < fan->fps_count; i++) {
+ if (control == fan->fps[i].control)
+ break;
+ }
+ if (i == fan->fps_count) {
+ dev_dbg(&device->dev, "Invalid control value returned\n");
+ status = -EINVAL;
+ goto err;
+ }
+
+ *state = i;
+
+err:
+ kfree(obj);
+ return status;
+}
+
+static int fan_get_state(struct acpi_device *device, unsigned long *state)
{
- struct acpi_device *device = cdev->devdata;
int result;
int acpi_state = ACPI_STATE_D0;
- if (!device)
- return -EINVAL;
-
- result = acpi_bus_update_power(device->handle, &acpi_state);
+ result = acpi_device_update_power(device, &acpi_state);
if (result)
return result;
@@ -103,21 +163,57 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
return 0;
}
-static int
-fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
+static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
+ *state)
{
struct acpi_device *device = cdev->devdata;
- int result;
+ struct acpi_fan *fan = acpi_driver_data(device);
- if (!device || (state != 0 && state != 1))
+ if (fan->acpi4)
+ return fan_get_state_acpi4(device, state);
+ else
+ return fan_get_state(device, state);
+}
+
+static int fan_set_state(struct acpi_device *device, unsigned long state)
+{
+ if (state != 0 && state != 1)
return -EINVAL;
- result = acpi_bus_set_power(device->handle,
- state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
+ return acpi_device_set_power(device,
+ state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
+}
- return result;
+static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
+{
+ struct acpi_fan *fan = acpi_driver_data(device);
+ acpi_status status;
+
+ if (state >= fan->fps_count)
+ return -EINVAL;
+
+ status = acpi_execute_simple_method(device->handle, "_FSL",
+ fan->fps[state].control);
+ if (ACPI_FAILURE(status)) {
+ dev_dbg(&device->dev, "Failed to set state by _FSL\n");
+ return status;
+ }
+
+ return 0;
}
+static int
+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_fan *fan = acpi_driver_data(device);
+
+ if (fan->acpi4)
+ return fan_set_state_acpi4(device, state);
+ else
+ return fan_set_state(device, state);
+ }
+
static const struct thermal_cooling_device_ops fan_cooling_ops = {
.get_max_state = fan_get_max_state,
.get_cur_state = fan_get_cur_state,
@@ -129,21 +225,125 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = {
* --------------------------------------------------------------------------
*/
-static int acpi_fan_add(struct acpi_device *device)
+static bool acpi_fan_is_acpi4(struct acpi_device *device)
{
- int result = 0;
- struct thermal_cooling_device *cdev;
+ return acpi_has_method(device->handle, "_FIF") &&
+ acpi_has_method(device->handle, "_FPS") &&
+ acpi_has_method(device->handle, "_FSL") &&
+ acpi_has_method(device->handle, "_FST");
+}
- if (!device)
- return -EINVAL;
+static int acpi_fan_get_fif(struct acpi_device *device)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_fan *fan = acpi_driver_data(device);
+ struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
+ struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
+ union acpi_object *obj;
+ acpi_status status;
+
+ status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = buffer.pointer;
+ if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
+ dev_err(&device->dev, "Invalid _FIF data\n");
+ status = -EINVAL;
+ goto err;
+ }
- strcpy(acpi_device_name(device), "Fan");
- strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
+ status = acpi_extract_package(obj, &format, &fif);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&device->dev, "Invalid _FIF element\n");
+ status = -EINVAL;
+ }
- result = acpi_bus_update_power(device->handle, NULL);
- if (result) {
- dev_err(&device->dev, "Setting initial power state\n");
- goto end;
+err:
+ kfree(obj);
+ return status;
+}
+
+static int acpi_fan_speed_cmp(const void *a, const void *b)
+{
+ const struct acpi_fan_fps *fps1 = a;
+ const struct acpi_fan_fps *fps2 = b;
+ return fps1->speed - fps2->speed;
+}
+
+static int acpi_fan_get_fps(struct acpi_device *device)
+{
+ struct acpi_fan *fan = acpi_driver_data(device);
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = buffer.pointer;
+ if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
+ dev_err(&device->dev, "Invalid _FPS data\n");
+ status = -EINVAL;
+ goto err;
+ }
+
+ fan->fps_count = obj->package.count - 1; /* minus revision field */
+ fan->fps = devm_kzalloc(&device->dev,
+ fan->fps_count * sizeof(struct acpi_fan_fps),
+ GFP_KERNEL);
+ if (!fan->fps) {
+ dev_err(&device->dev, "Not enough memory\n");
+ status = -ENOMEM;
+ goto err;
+ }
+ for (i = 0; i < fan->fps_count; i++) {
+ struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+ struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] };
+ status = acpi_extract_package(&obj->package.elements[i + 1],
+ &format, &fps);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&device->dev, "Invalid _FPS element\n");
+ break;
+ }
+ }
+
+ /* sort the state array according to fan speed in increase order */
+ sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
+ acpi_fan_speed_cmp, NULL);
+
+err:
+ kfree(obj);
+ return status;
+}
+
+static int acpi_fan_probe(struct platform_device *pdev)
+{
+ int result = 0;
+ struct thermal_cooling_device *cdev;
+ struct acpi_fan *fan;
+ struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+
+ fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
+ if (!fan) {
+ dev_err(&device->dev, "No memory for fan\n");
+ return -ENOMEM;
+ }
+ device->driver_data = fan;
+ platform_set_drvdata(pdev, fan);
+
+ if (acpi_fan_is_acpi4(device)) {
+ if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device))
+ goto end;
+ fan->acpi4 = true;
+ } else {
+ result = acpi_device_update_power(device, NULL);
+ if (result) {
+ dev_err(&device->dev, "Setting initial power state\n");
+ goto end;
+ }
}
cdev = thermal_cooling_device_register("Fan", device,
@@ -153,44 +353,32 @@ static int acpi_fan_add(struct acpi_device *device)
goto end;
}
- dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id);
+ dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
- device->driver_data = cdev;
- result = sysfs_create_link(&device->dev.kobj,
+ fan->cdev = cdev;
+ result = sysfs_create_link(&pdev->dev.kobj,
&cdev->device.kobj,
"thermal_cooling");
if (result)
- dev_err(&device->dev, "Failed to create sysfs link "
- "'thermal_cooling'\n");
+ dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n");
result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj,
+ &pdev->dev.kobj,
"device");
if (result)
- dev_err(&device->dev, "Failed to create sysfs link 'device'\n");
-
- dev_info(&device->dev, "ACPI: %s [%s] (%s)\n",
- acpi_device_name(device), acpi_device_bid(device),
- !device->power.state ? "on" : "off");
+ dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
end:
return result;
}
-static int acpi_fan_remove(struct acpi_device *device)
+static int acpi_fan_remove(struct platform_device *pdev)
{
- struct thermal_cooling_device *cdev;
-
- if (!device)
- return -EINVAL;
-
- cdev = acpi_driver_data(device);
- if (!cdev)
- return -EINVAL;
+ struct acpi_fan *fan = platform_get_drvdata(pdev);
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- sysfs_remove_link(&cdev->device.kobj, "device");
- thermal_cooling_device_unregister(cdev);
+ sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
+ sysfs_remove_link(&fan->cdev->device.kobj, "device");
+ thermal_cooling_device_unregister(fan->cdev);
return 0;
}
@@ -198,10 +386,11 @@ static int acpi_fan_remove(struct acpi_device *device)
#ifdef CONFIG_PM_SLEEP
static int acpi_fan_suspend(struct device *dev)
{
- if (!dev)
- return -EINVAL;
+ struct acpi_fan *fan = dev_get_drvdata(dev);
+ if (fan->acpi4)
+ return 0;
- acpi_bus_set_power(to_acpi_device(dev)->handle, ACPI_STATE_D0);
+ acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
return AE_OK;
}
@@ -209,11 +398,12 @@ static int acpi_fan_suspend(struct device *dev)
static int acpi_fan_resume(struct device *dev)
{
int result;
+ struct acpi_fan *fan = dev_get_drvdata(dev);
- if (!dev)
- return -EINVAL;
+ if (fan->acpi4)
+ return 0;
- result = acpi_bus_update_power(to_acpi_device(dev)->handle, NULL);
+ result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
if (result)
dev_err(dev, "Error updating fan power state\n");
@@ -221,4 +411,4 @@ static int acpi_fan_resume(struct device *dev)
}
#endif
-module_acpi_driver(acpi_fan_driver);
+module_platform_driver(acpi_fan_driver);
diff --git a/drivers/acpi/int340x_thermal.c b/drivers/acpi/int340x_thermal.c
new file mode 100644
index 000000000000..a27d31d1ba24
--- /dev/null
+++ b/drivers/acpi/int340x_thermal.c
@@ -0,0 +1,51 @@
+/*
+ * ACPI support for int340x thermal drivers
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Zhang Rui <rui.zhang@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/acpi.h>
+#include <linux/module.h>
+
+#include "internal.h"
+
+#define DO_ENUMERATION 0x01
+static const struct acpi_device_id int340x_thermal_device_ids[] = {
+ {"INT3400", DO_ENUMERATION },
+ {"INT3401"},
+ {"INT3402"},
+ {"INT3403"},
+ {"INT3404"},
+ {"INT3406"},
+ {"INT3407"},
+ {"INT3408"},
+ {"INT3409"},
+ {"INT340A"},
+ {"INT340B"},
+ {""},
+};
+
+static int int340x_thermal_handler_attach(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+#if defined(CONFIG_INT340X_THERMAL) || defined(CONFIG_INT340X_THERMAL_MODULE)
+ if (id->driver_data == DO_ENUMERATION)
+ acpi_create_platform_device(adev);
+#endif
+ return 1;
+}
+
+static struct acpi_scan_handler int340x_thermal_handler = {
+ .ids = int340x_thermal_device_ids,
+ .attach = int340x_thermal_handler_attach,
+};
+
+void __init acpi_int340x_thermal_init(void)
+{
+ acpi_scan_add_handler(&int340x_thermal_handler);
+}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 4c5cf77e7576..163e82f536fa 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,7 @@ void acpi_pci_link_init(void);
void acpi_processor_init(void);
void acpi_platform_init(void);
void acpi_pnp_init(void);
+void acpi_int340x_thermal_init(void);
int acpi_sysfs_init(void);
void acpi_container_init(void);
void acpi_memory_hotplug_init(void);
@@ -103,8 +104,6 @@ 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);
#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
@@ -168,17 +167,16 @@ static inline void suspend_nvs_restore(void) {}
#endif
/*--------------------------------------------------------------------------
- Platform bus support
- -------------------------------------------------------------------------- */
-struct platform_device;
-
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
-
-/*--------------------------------------------------------------------------
Video
-------------------------------------------------------------------------- */
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
bool acpi_osi_is_win8(void);
#endif
+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 9964f70be98d..f9eeae871593 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -436,7 +436,7 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
static void acpi_os_map_cleanup(struct acpi_ioremap *map)
{
if (!map->refcount) {
- synchronize_rcu();
+ synchronize_rcu_expedited();
acpi_unmap(map->phys, map->virt);
kfree(map);
}
@@ -1188,6 +1188,12 @@ EXPORT_SYMBOL(acpi_os_execute);
void acpi_os_wait_events_complete(void)
{
+ /*
+ * Make sure the GPE handler or the fixed event handler is not used
+ * on another CPU after removal.
+ */
+ if (acpi_irq_handler)
+ synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 6e6b80eb0bba..7cc4e33179f9 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -484,7 +484,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
/* Keep IOAPIC pin configuration when suspending */
if (dev->dev.power.is_prepared)
return;
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
if (dev->dev.power.runtime_status == RPM_SUSPENDING)
return;
#endif
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index cd4de7e038ea..c6bcb8c719d8 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-aspm.h>
+#include <linux/dmar.h>
#include <linux/acpi.h>
#include <linux/slab.h>
#include <linux/dmi.h>
@@ -525,6 +526,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
struct acpi_pci_root *root;
acpi_handle handle = device->handle;
int no_aspm = 0, clear_aspm = 0;
+ bool hotadd = system_state != SYSTEM_BOOTING;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
@@ -571,6 +573,11 @@ static int acpi_pci_root_add(struct acpi_device *device,
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root;
+ if (hotadd && dmar_device_add(handle)) {
+ result = -ENXIO;
+ goto end;
+ }
+
pr_info(PREFIX "%s [%s] (domain %04x %pR)\n",
acpi_device_name(device), acpi_device_bid(device),
root->segment, &root->secondary);
@@ -597,7 +604,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
root->segment, (unsigned int)root->secondary.start);
device->driver_data = NULL;
result = -ENODEV;
- goto end;
+ goto remove_dmar;
}
if (clear_aspm) {
@@ -611,7 +618,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
- if (system_state != SYSTEM_BOOTING) {
+ if (hotadd) {
pcibios_resource_survey_bus(root->bus);
pci_assign_unassigned_root_bus_resources(root->bus);
}
@@ -621,6 +628,9 @@ static int acpi_pci_root_add(struct acpi_device *device,
pci_unlock_rescan_remove();
return 1;
+remove_dmar:
+ if (hotadd)
+ dmar_device_remove(handle);
end:
kfree(root);
return result;
@@ -639,6 +649,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
pci_remove_root_bus(root->bus);
+ dmar_device_remove(device->handle);
+
pci_unlock_rescan_remove();
kfree(root);
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
new file mode 100644
index 000000000000..a732e5d7e322
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -0,0 +1,354 @@
+/*
+ * intel_pmic.c - Intel PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include "intel_pmic.h"
+
+#define PMIC_POWER_OPREGION_ID 0x8d
+#define PMIC_THERMAL_OPREGION_ID 0x8c
+
+struct acpi_lpat {
+ int temp;
+ int raw;
+};
+
+struct intel_pmic_opregion {
+ struct mutex lock;
+ struct acpi_lpat *lpat;
+ int lpat_count;
+ struct regmap *regmap;
+ struct intel_pmic_opregion_data *data;
+};
+
+static int pmic_get_reg_bit(int address, struct pmic_table *table,
+ int count, int *reg, int *bit)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (table[i].address == address) {
+ *reg = table[i].reg;
+ if (bit)
+ *bit = table[i].bit;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * raw_to_temp(): Return temperature from raw value through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @raw: the raw value, used as a key to get the temerature from the
+ * above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
+{
+ int i, delta_temp, delta_raw, temp;
+
+ for (i = 0; i < count - 1; i++) {
+ if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
+ (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
+ break;
+ }
+
+ if (i == count - 1)
+ return -ENOENT;
+
+ delta_temp = lpat[i+1].temp - lpat[i].temp;
+ delta_raw = lpat[i+1].raw - lpat[i].raw;
+ temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
+
+ return temp;
+}
+
+/**
+ * temp_to_raw(): Return raw value from temperature through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @temp: the temperature, used as a key to get the raw value from the
+ * above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
+{
+ int i, delta_temp, delta_raw, raw;
+
+ for (i = 0; i < count - 1; i++) {
+ if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
+ break;
+ }
+
+ if (i == count - 1)
+ return -ENOENT;
+
+ delta_temp = lpat[i+1].temp - lpat[i].temp;
+ delta_raw = lpat[i+1].raw - lpat[i].raw;
+ raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
+
+ return raw;
+}
+
+static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
+ acpi_handle handle, struct device *dev)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj_p, *obj_e;
+ int *lpat, i;
+ acpi_status status;
+
+ status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return;
+
+ obj_p = (union acpi_object *)buffer.pointer;
+ if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
+ (obj_p->package.count % 2) || (obj_p->package.count < 4))
+ goto out;
+
+ lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
+ GFP_KERNEL);
+ if (!lpat)
+ goto out;
+
+ for (i = 0; i < obj_p->package.count; i++) {
+ obj_e = &obj_p->package.elements[i];
+ if (obj_e->type != ACPI_TYPE_INTEGER) {
+ devm_kfree(dev, lpat);
+ goto out;
+ }
+ lpat[i] = (s64)obj_e->integer.value;
+ }
+
+ opregion->lpat = (struct acpi_lpat *)lpat;
+ opregion->lpat_count = obj_p->package.count / 2;
+
+out:
+ kfree(buffer.pointer);
+}
+
+static acpi_status intel_pmic_power_handler(u32 function,
+ acpi_physical_address address, u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ struct intel_pmic_opregion *opregion = region_context;
+ struct regmap *regmap = opregion->regmap;
+ struct intel_pmic_opregion_data *d = opregion->data;
+ int reg, bit, result;
+
+ if (bits != 32 || !value64)
+ return AE_BAD_PARAMETER;
+
+ if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
+ return AE_BAD_PARAMETER;
+
+ result = pmic_get_reg_bit(address, d->power_table,
+ d->power_table_count, &reg, &bit);
+ if (result == -ENOENT)
+ return AE_BAD_PARAMETER;
+
+ mutex_lock(&opregion->lock);
+
+ result = function == ACPI_READ ?
+ d->get_power(regmap, reg, bit, value64) :
+ d->update_power(regmap, reg, bit, *value64 == 1);
+
+ mutex_unlock(&opregion->lock);
+
+ return result ? AE_ERROR : AE_OK;
+}
+
+static int pmic_read_temp(struct intel_pmic_opregion *opregion,
+ int reg, u64 *value)
+{
+ int raw_temp, temp;
+
+ if (!opregion->data->get_raw_temp)
+ return -ENXIO;
+
+ raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
+ if (raw_temp < 0)
+ return raw_temp;
+
+ if (!opregion->lpat) {
+ *value = raw_temp;
+ return 0;
+ }
+
+ temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);
+ if (temp < 0)
+ return temp;
+
+ *value = temp;
+ return 0;
+}
+
+static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ return function == ACPI_READ ?
+ pmic_read_temp(opregion, reg, value) : -EINVAL;
+}
+
+static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ int raw_temp;
+
+ if (function == ACPI_READ)
+ return pmic_read_temp(opregion, reg, value);
+
+ if (!opregion->data->update_aux)
+ return -ENXIO;
+
+ if (opregion->lpat) {
+ raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
+ *value);
+ if (raw_temp < 0)
+ return raw_temp;
+ } else {
+ raw_temp = *value;
+ }
+
+ return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
+}
+
+static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ struct intel_pmic_opregion_data *d = opregion->data;
+ struct regmap *regmap = opregion->regmap;
+
+ if (!d->get_policy || !d->update_policy)
+ return -ENXIO;
+
+ if (function == ACPI_READ)
+ return d->get_policy(regmap, reg, value);
+
+ if (*value != 0 && *value != 1)
+ return -EINVAL;
+
+ return d->update_policy(regmap, reg, *value);
+}
+
+static bool pmic_thermal_is_temp(int address)
+{
+ return (address <= 0x3c) && !(address % 12);
+}
+
+static bool pmic_thermal_is_aux(int address)
+{
+ return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
+ (address >= 8 && address <= 0x44 && !((address - 8) % 12));
+}
+
+static bool pmic_thermal_is_pen(int address)
+{
+ return address >= 0x48 && address <= 0x5c;
+}
+
+static acpi_status intel_pmic_thermal_handler(u32 function,
+ acpi_physical_address address, u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ struct intel_pmic_opregion *opregion = region_context;
+ struct intel_pmic_opregion_data *d = opregion->data;
+ int reg, result;
+
+ if (bits != 32 || !value64)
+ return AE_BAD_PARAMETER;
+
+ result = pmic_get_reg_bit(address, d->thermal_table,
+ d->thermal_table_count, &reg, NULL);
+ if (result == -ENOENT)
+ return AE_BAD_PARAMETER;
+
+ mutex_lock(&opregion->lock);
+
+ if (pmic_thermal_is_temp(address))
+ result = pmic_thermal_temp(opregion, reg, function, value64);
+ else if (pmic_thermal_is_aux(address))
+ result = pmic_thermal_aux(opregion, reg, function, value64);
+ else if (pmic_thermal_is_pen(address))
+ result = pmic_thermal_pen(opregion, reg, function, value64);
+ else
+ result = -EINVAL;
+
+ mutex_unlock(&opregion->lock);
+
+ if (result < 0) {
+ if (result == -EINVAL)
+ return AE_BAD_PARAMETER;
+ else
+ return AE_ERROR;
+ }
+
+ return AE_OK;
+}
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
+ struct regmap *regmap,
+ struct intel_pmic_opregion_data *d)
+{
+ acpi_status status;
+ struct intel_pmic_opregion *opregion;
+
+ if (!dev || !regmap || !d)
+ return -EINVAL;
+
+ if (!handle)
+ return -ENODEV;
+
+ opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
+ if (!opregion)
+ return -ENOMEM;
+
+ mutex_init(&opregion->lock);
+ opregion->regmap = regmap;
+ pmic_thermal_lpat(opregion, handle, dev);
+
+ status = acpi_install_address_space_handler(handle,
+ PMIC_POWER_OPREGION_ID,
+ intel_pmic_power_handler,
+ NULL, opregion);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ status = acpi_install_address_space_handler(handle,
+ PMIC_THERMAL_OPREGION_ID,
+ intel_pmic_thermal_handler,
+ NULL, opregion);
+ if (ACPI_FAILURE(status)) {
+ acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
+ intel_pmic_power_handler);
+ return -ENODEV;
+ }
+
+ opregion->data = d;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h
new file mode 100644
index 000000000000..d4e90af8f0dd
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic.h
@@ -0,0 +1,25 @@
+#ifndef __INTEL_PMIC_H
+#define __INTEL_PMIC_H
+
+struct pmic_table {
+ int address; /* operation region address */
+ int reg; /* corresponding thermal register */
+ int bit; /* control bit for power */
+};
+
+struct intel_pmic_opregion_data {
+ int (*get_power)(struct regmap *r, int reg, int bit, u64 *value);
+ int (*update_power)(struct regmap *r, int reg, int bit, bool on);
+ int (*get_raw_temp)(struct regmap *r, int reg);
+ int (*update_aux)(struct regmap *r, int reg, int raw_temp);
+ int (*get_policy)(struct regmap *r, int reg, u64 *value);
+ int (*update_policy)(struct regmap *r, int reg, int enable);
+ struct pmic_table *power_table;
+ int power_table_count;
+ struct pmic_table *thermal_table;
+ int thermal_table_count;
+};
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d);
+
+#endif
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c
new file mode 100644
index 000000000000..ef7d8ff95abe
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic_crc.c
@@ -0,0 +1,211 @@
+/*
+ * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include "intel_pmic.h"
+
+#define PWR_SOURCE_SELECT BIT(1)
+
+#define PMIC_A0LOCK_REG 0xc5
+
+static struct pmic_table power_table[] = {
+ {
+ .address = 0x24,
+ .reg = 0x66,
+ .bit = 0x00,
+ },
+ {
+ .address = 0x48,
+ .reg = 0x5d,
+ .bit = 0x00,
+ },
+};
+
+static struct pmic_table thermal_table[] = {
+ {
+ .address = 0x00,
+ .reg = 0x75
+ },
+ {
+ .address = 0x04,
+ .reg = 0x95
+ },
+ {
+ .address = 0x08,
+ .reg = 0x97
+ },
+ {
+ .address = 0x0c,
+ .reg = 0x77
+ },
+ {
+ .address = 0x10,
+ .reg = 0x9a
+ },
+ {
+ .address = 0x14,
+ .reg = 0x9c
+ },
+ {
+ .address = 0x18,
+ .reg = 0x79
+ },
+ {
+ .address = 0x1c,
+ .reg = 0x9f
+ },
+ {
+ .address = 0x20,
+ .reg = 0xa1
+ },
+ {
+ .address = 0x48,
+ .reg = 0x94
+ },
+ {
+ .address = 0x4c,
+ .reg = 0x99
+ },
+ {
+ .address = 0x50,
+ .reg = 0x9e
+ },
+};
+
+static int intel_crc_pmic_get_power(struct regmap *regmap, int reg,
+ int bit, u64 *value)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0;
+ return 0;
+}
+
+static int intel_crc_pmic_update_power(struct regmap *regmap, int reg,
+ int bit, bool on)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ if (on) {
+ data |= PWR_SOURCE_SELECT | BIT(bit);
+ } else {
+ data &= ~BIT(bit);
+ data |= PWR_SOURCE_SELECT;
+ }
+
+ if (regmap_write(regmap, reg, data))
+ return -EIO;
+ return 0;
+}
+
+static int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+ int temp_l, temp_h;
+
+ /*
+ * Raw temperature value is 10bits: 8bits in reg
+ * and 2bits in reg-1: bit0,1
+ */
+ if (regmap_read(regmap, reg, &temp_l) ||
+ regmap_read(regmap, reg - 1, &temp_h))
+ return -EIO;
+
+ return temp_l | (temp_h & 0x3) << 8;
+}
+
+static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw)
+{
+ return regmap_write(regmap, reg, raw) ||
+ regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0;
+}
+
+static int intel_crc_pmic_get_policy(struct regmap *regmap, int reg, u64 *value)
+{
+ int pen;
+
+ if (regmap_read(regmap, reg, &pen))
+ return -EIO;
+ *value = pen >> 7;
+ return 0;
+}
+
+static int intel_crc_pmic_update_policy(struct regmap *regmap,
+ int reg, int enable)
+{
+ int alert0;
+
+ /* Update to policy enable bit requires unlocking a0lock */
+ if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0))
+ return -EIO;
+
+ if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0))
+ return -EIO;
+
+ if (regmap_update_bits(regmap, reg, 0x80, enable << 7))
+ return -EIO;
+
+ /* restore alert0 */
+ if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0))
+ return -EIO;
+
+ return 0;
+}
+
+static struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = {
+ .get_power = intel_crc_pmic_get_power,
+ .update_power = intel_crc_pmic_update_power,
+ .get_raw_temp = intel_crc_pmic_get_raw_temp,
+ .update_aux = intel_crc_pmic_update_aux,
+ .get_policy = intel_crc_pmic_get_policy,
+ .update_policy = intel_crc_pmic_update_policy,
+ .power_table = power_table,
+ .power_table_count= ARRAY_SIZE(power_table),
+ .thermal_table = thermal_table,
+ .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
+{
+ struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+ return intel_pmic_install_opregion_handler(&pdev->dev,
+ ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
+ &intel_crc_pmic_opregion_data);
+}
+
+static struct platform_driver intel_crc_pmic_opregion_driver = {
+ .probe = intel_crc_pmic_opregion_probe,
+ .driver = {
+ .name = "crystal_cove_pmic",
+ },
+};
+
+static int __init intel_crc_pmic_opregion_driver_init(void)
+{
+ return platform_driver_register(&intel_crc_pmic_opregion_driver);
+}
+module_init(intel_crc_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("CrystalCove ACPI opration region driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
new file mode 100644
index 000000000000..6a082d4de12c
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -0,0 +1,268 @@
+/*
+ * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/iio/consumer.h>
+#include "intel_pmic.h"
+
+#define XPOWER_GPADC_LOW 0x5b
+
+static struct pmic_table power_table[] = {
+ {
+ .address = 0x00,
+ .reg = 0x13,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x04,
+ .reg = 0x13,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x08,
+ .reg = 0x13,
+ .bit = 0x07,
+ },
+ {
+ .address = 0x0c,
+ .reg = 0x12,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x10,
+ .reg = 0x12,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x14,
+ .reg = 0x12,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x18,
+ .reg = 0x12,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x1c,
+ .reg = 0x12,
+ .bit = 0x00,
+ },
+ {
+ .address = 0x20,
+ .reg = 0x12,
+ .bit = 0x01,
+ },
+ {
+ .address = 0x24,
+ .reg = 0x12,
+ .bit = 0x02,
+ },
+ {
+ .address = 0x28,
+ .reg = 0x13,
+ .bit = 0x02,
+ },
+ {
+ .address = 0x2c,
+ .reg = 0x13,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x30,
+ .reg = 0x13,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x38,
+ .reg = 0x10,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x3c,
+ .reg = 0x10,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x40,
+ .reg = 0x10,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x44,
+ .reg = 0x10,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x48,
+ .reg = 0x10,
+ .bit = 0x01,
+ },
+ {
+ .address = 0x4c,
+ .reg = 0x10,
+ .bit = 0x00
+ },
+};
+
+/* TMP0 - TMP5 are the same, all from GPADC */
+static struct pmic_table thermal_table[] = {
+ {
+ .address = 0x00,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x0c,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x18,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x24,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x30,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x3c,
+ .reg = XPOWER_GPADC_LOW
+ },
+};
+
+static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
+ int bit, u64 *value)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ *value = (data & BIT(bit)) ? 1 : 0;
+ return 0;
+}
+
+static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
+ int bit, bool on)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ if (on)
+ data |= BIT(bit);
+ else
+ data &= ~BIT(bit);
+
+ if (regmap_write(regmap, reg, data))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
+ *
+ * @regmap: regmap of the PMIC device
+ * @reg: register to get the reading
+ *
+ * We could get the sensor value by manipulating the HW regs here, but since
+ * the axp288 IIO driver may also access the same regs at the same time, the
+ * APIs provided by IIO subsystem are used here instead to avoid problems. As
+ * a result, the two passed in params are of no actual use.
+ *
+ * Return a positive value on success, errno on failure.
+ */
+static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+ struct iio_channel *gpadc_chan;
+ int ret, val;
+
+ gpadc_chan = iio_channel_get(NULL, "axp288-system-temp");
+ if (IS_ERR_OR_NULL(gpadc_chan))
+ return -EACCES;
+
+ ret = iio_read_channel_raw(gpadc_chan, &val);
+ if (ret < 0)
+ val = ret;
+
+ iio_channel_release(gpadc_chan);
+ return val;
+}
+
+static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
+ .get_power = intel_xpower_pmic_get_power,
+ .update_power = intel_xpower_pmic_update_power,
+ .get_raw_temp = intel_xpower_pmic_get_raw_temp,
+ .power_table = power_table,
+ .power_table_count = ARRAY_SIZE(power_table),
+ .thermal_table = thermal_table,
+ .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
+ acpi_physical_address address, u32 bit_width, u64 *value,
+ void *handler_context, void *region_context)
+{
+ return AE_OK;
+}
+
+static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
+{
+ struct device *parent = pdev->dev.parent;
+ struct axp20x_dev *axp20x = dev_get_drvdata(parent);
+ acpi_status status;
+ int result;
+
+ status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
+ ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ result = intel_pmic_install_opregion_handler(&pdev->dev,
+ ACPI_HANDLE(parent), axp20x->regmap,
+ &intel_xpower_pmic_opregion_data);
+ if (result)
+ acpi_remove_address_space_handler(ACPI_HANDLE(parent),
+ ACPI_ADR_SPACE_GPIO,
+ intel_xpower_pmic_gpio_handler);
+
+ return result;
+}
+
+static struct platform_driver intel_xpower_pmic_opregion_driver = {
+ .probe = intel_xpower_pmic_opregion_probe,
+ .driver = {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
+static int __init intel_xpower_pmic_opregion_driver_init(void)
+{
+ return platform_driver_register(&intel_xpower_pmic_opregion_driver);
+}
+module_init(intel_xpower_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("XPower AXP288 ACPI operation region driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 17f9ec501972..499536504698 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -334,10 +334,10 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
{
- acpi_status status = 0;
+ acpi_status status;
u64 count;
int current_count;
- int i;
+ int i, ret = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cst;
@@ -358,7 +358,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
printk(KERN_ERR PREFIX "not enough elements in _CST\n");
- status = -EFAULT;
+ ret = -EFAULT;
goto end;
}
@@ -367,7 +367,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* Validate number of power states. */
if (count < 1 || count != cst->package.count - 1) {
printk(KERN_ERR PREFIX "count given by _CST is not valid\n");
- status = -EFAULT;
+ ret = -EFAULT;
goto end;
}
@@ -489,12 +489,12 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* Validate number of power states discovered */
if (current_count < 2)
- status = -EFAULT;
+ ret = -EFAULT;
end:
kfree(buffer.pointer);
- return status;
+ return ret;
}
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
@@ -985,8 +985,8 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
- if (cx->entry_method == ACPI_CSTATE_FFH)
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ if (cx->entry_method != ACPI_CSTATE_FFH)
+ state->flags |= CPUIDLE_FLAG_TIME_INVALID;
state->enter = acpi_idle_enter_c1;
state->enter_dead = acpi_idle_play_dead;
@@ -994,14 +994,12 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
break;
case ACPI_STATE_C2:
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
state->enter_dead = acpi_idle_play_dead;
drv->safe_state_index = count;
break;
case ACPI_STATE_C3:
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = pr->flags.bm_check ?
acpi_idle_enter_bm :
acpi_idle_enter_simple;
@@ -1111,7 +1109,7 @@ static int acpi_processor_registered;
int acpi_processor_power_init(struct acpi_processor *pr)
{
- acpi_status status = 0;
+ acpi_status status;
int retval;
struct cpuidle_device *dev;
static int first_run;
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
new file mode 100644
index 000000000000..0d083736e25b
--- /dev/null
+++ b/drivers/acpi/property.c
@@ -0,0 +1,551 @@
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Darren Hart <dvhart@linux.intel.com>
+ * 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/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+ int j;
+
+ /*
+ * The value must be an integer, a string, a reference, or a package
+ * whose every element must be an integer, a string, or a reference.
+ */
+ switch (value->type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return true;
+
+ case ACPI_TYPE_PACKAGE:
+ for (j = 0; j < value->package.count; j++)
+ switch (value->package.elements[j].type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ continue;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+ int i;
+
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+ /*
+ * Only two elements allowed, the first one must be a string and
+ * the second one has to satisfy certain conditions.
+ */
+ if (property->package.count != 2
+ || property->package.elements[0].type != ACPI_TYPE_STRING
+ || !acpi_property_value_ok(&property->package.elements[1]))
+ return false;
+ }
+ return true;
+}
+
+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+ int ret;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible);
+ if (ret) {
+ ret = acpi_dev_get_property(adev, "compatible",
+ ACPI_TYPE_STRING, &of_compatible);
+ if (ret) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+ }
+ adev->data.of_compatible = of_compatible;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *desc;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return;
+
+ desc = buf.pointer;
+ if (desc->package.count % 2)
+ goto fail;
+
+ /* Look for the device properties UUID. */
+ for (i = 0; i < desc->package.count; i += 2) {
+ const union acpi_object *uuid, *properties;
+
+ uuid = &desc->package.elements[i];
+ properties = &desc->package.elements[i + 1];
+
+ /*
+ * The first element must be a UUID and the second one must be
+ * a package.
+ */
+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+ || properties->type != ACPI_TYPE_PACKAGE)
+ break;
+
+ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+ continue;
+
+ /*
+ * We found the matching UUID. Now validate the format of the
+ * package immediately following it.
+ */
+ if (!acpi_properties_format_valid(properties))
+ break;
+
+ adev->data.pointer = buf.pointer;
+ adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
+ return;
+ }
+
+ fail:
+ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
+ adev->data.pointer = NULL;
+ adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected property type
+ * @obj: Location to store the property value (if not %NULL)
+ *
+ * Look up a property with @name and store a pointer to the resulting ACPI
+ * object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. These objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if property with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property value type doesn't match @type.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ const union acpi_object *properties;
+ int i;
+
+ if (!adev || !name)
+ return -EINVAL;
+
+ if (!adev->data.pointer || !adev->data.properties)
+ return -ENODATA;
+
+ properties = adev->data.properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
+
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY && propvalue->type != type)
+ return -EPROTO;
+ else if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected type of array elements
+ * @obj: Location to store a pointer to the property value (if not NULL)
+ *
+ * Look up an array property with @name and store a pointer to the resulting
+ * ACPI object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. Those objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if array property (package) with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property is not a package or the type of its elements
+ * doesn't match @type.
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ const union acpi_object *prop;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+ if (ret)
+ return ret;
+
+ if (type != ACPI_TYPE_ANY) {
+ /* Check that all elements are of correct type. */
+ for (i = 0; i < prop->package.count; i++)
+ if (prop->package.elements[i].type != type)
+ return -EPROTO;
+ }
+ if (obj)
+ *obj = prop;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @index: Index of the reference to return
+ * @args: Location to store the returned reference with optional arguments
+ *
+ * Find property with @name, verifify that it is a package containing at least
+ * one object reference and if so, store the ACPI device object pointer to the
+ * target object in @args->adev. If the reference includes arguments, store
+ * them in the @args->args[] array.
+ *
+ * If there's more than one reference in the property value package, @index is
+ * used to select the one to return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, size_t index,
+ struct acpi_reference_args *args)
+{
+ const union acpi_object *element, *end;
+ const union acpi_object *obj;
+ struct acpi_device *device;
+ int ret, idx = 0;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ /*
+ * The simplest case is when the value is a single reference. Just
+ * return that reference then.
+ */
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+ if (index)
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(obj->reference.handle, &device);
+ if (ret)
+ return ret;
+
+ args->adev = device;
+ args->nargs = 0;
+ return 0;
+ }
+
+ /*
+ * If it is not a single reference, then it is a package of
+ * references followed by number of ints as follows:
+ *
+ * Package () { REF, INT, REF, INT, INT }
+ *
+ * The index argument is then used to determine which reference
+ * the caller wants (along with the arguments).
+ */
+ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+ return -EPROTO;
+
+ element = obj->package.elements;
+ end = element + obj->package.count;
+
+ while (element < end) {
+ u32 nargs, i;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ return -EPROTO;
+
+ ret = acpi_bus_get_device(element->reference.handle, &device);
+ if (ret)
+ return -ENODEV;
+
+ element++;
+ nargs = 0;
+
+ /* assume following integer elements are all args */
+ for (i = 0; element + i < end; i++) {
+ int type = element[i].type;
+
+ if (type == ACPI_TYPE_INTEGER)
+ nargs++;
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
+ else
+ return -EPROTO;
+ }
+
+ if (idx++ == index) {
+ args->adev = device;
+ args->nargs = nargs;
+ for (i = 0; i < nargs; i++)
+ args->args[i] = element[i].integer.value;
+
+ return 0;
+ }
+
+ element += nargs;
+ }
+
+ return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr)
+{
+ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ if (!val)
+ return -EINVAL;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ if (obj->integer.value > U8_MAX)
+ return -EOVERFLOW;
+ *(u8 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U16:
+ if (obj->integer.value > U16_MAX)
+ return -EOVERFLOW;
+ *(u16 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U32:
+ if (obj->integer.value > U32_MAX)
+ return -EOVERFLOW;
+ *(u32 *)val = obj->integer.value;
+ break;
+ default:
+ *(u64 *)val = obj->integer.value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ *(char **)val = obj->string.pointer;
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+ size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U8_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+ u16 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U16_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+ u32 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U32_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+ u64 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+ char **val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_STRING)
+ return -EPROTO;
+
+ val[i] = items[i].string.pointer;
+ }
+ return 0;
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval)
+{
+ const union acpi_object *obj;
+ const union acpi_object *items;
+ int ret;
+
+ if (val && nval == 1) {
+ ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
+ if (!ret)
+ return ret;
+ }
+
+ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return obj->package.count;
+ else if (nval <= 0)
+ return -EINVAL;
+
+ if (nval > obj->package.count)
+ return -EOVERFLOW;
+
+ items = obj->package.elements;
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = acpi_copy_property_array_string(items, (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ae44d8654c82..1b1cf558d3d3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -36,6 +36,8 @@ bool acpi_force_hot_remove;
static const char *dummy_hid = "device";
+static LIST_HEAD(acpi_dep_list);
+static DEFINE_MUTEX(acpi_dep_list_lock);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
@@ -43,6 +45,12 @@ DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
static DEFINE_MUTEX(acpi_hp_context_lock);
+struct acpi_dep_data {
+ struct list_head node;
+ acpi_handle master;
+ acpi_handle slave;
+};
+
struct acpi_device_bus_id{
char bus_id[15];
unsigned int instance_no;
@@ -124,17 +132,56 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;
- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ int i, nval;
+ char *c;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+ nval = of_compatible->package.count;
+ obj = of_compatible->package.elements;
+ } else { /* Must be ACPI_TYPE_STRING. */
+ nval = 1;
+ obj = of_compatible;
+ }
+ for (i = 0; i < nval; i++, obj++) {
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}
modalias[len] = '\0';
@@ -142,6 +189,53 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
}
/*
+ * acpi_companion_match() - Can we match via ACPI companion device
+ * @dev: Device in question
+ *
+ * Check if the given device has an ACPI companion and if that companion has
+ * a valid list of PNP IDs, and if the device is the first (primary) physical
+ * device associated with it.
+ *
+ * If multiple physical devices are attached to a single ACPI companion, we need
+ * to be careful. The usage scenario for this kind of relationship is that all
+ * of the physical devices in question use resources provided by the ACPI
+ * companion. A typical case is an MFD device where all the sub-devices share
+ * the parent's ACPI companion. In such cases we can only allow the primary
+ * (first) physical device to be matched with the help of the companion's PNP
+ * IDs.
+ *
+ * Additional physical devices sharing the ACPI companion can still use
+ * resources available from it but they will be matched normally using functions
+ * provided by their bus types (and analogously for their modalias).
+ */
+static bool acpi_companion_match(const struct device *dev)
+{
+ struct acpi_device *adev;
+ bool ret;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ if (list_empty(&adev->pnp.ids))
+ return false;
+
+ mutex_lock(&adev->physical_node_lock);
+ if (list_empty(&adev->physical_node_list)) {
+ ret = false;
+ } else {
+ const struct acpi_device_physical_node *node;
+
+ node = list_first_entry(&adev->physical_node_list,
+ struct acpi_device_physical_node, node);
+ ret = node->dev == dev;
+ }
+ mutex_unlock(&adev->physical_node_lock);
+
+ return ret;
+}
+
+/*
* 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:
@@ -149,20 +243,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
*/
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))
+ if (!acpi_companion_match(dev))
return -ENODEV;
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+ len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen);
if (len <= 0)
return len;
@@ -179,18 +267,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
*/
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))
+ if (!acpi_companion_match(dev))
return -ENODEV;
- len = create_modalias(acpi_dev, buf, size -1);
+ len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
if (len <= 0)
return len;
buf[len++] = '\n';
@@ -853,6 +935,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
if (!ids || !handle || acpi_bus_get_device(handle, &adev))
return NULL;
+ if (!acpi_companion_match(dev))
+ return NULL;
+
return __acpi_match_device(adev, ids);
}
EXPORT_SYMBOL_GPL(acpi_match_device);
@@ -864,6 +949,51 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible, *obj;
+ struct acpi_device *adev;
+ int i, nval;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+ nval = of_compatible->package.count;
+ obj = of_compatible->package.elements;
+ } else { /* Must be ACPI_TYPE_STRING. */
+ nval = 1;
+ obj = of_compatible;
+ }
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < nval; i++, obj++) {
+ const struct of_device_id *id;
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
@@ -884,6 +1014,7 @@ static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
@@ -1266,6 +1397,26 @@ int acpi_device_add(struct acpi_device *device,
return result;
}
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
@@ -1470,7 +1621,7 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device)
if (ACPI_FAILURE(status))
return;
- wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HANDLE);
+ wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER);
}
static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
@@ -1885,9 +2036,11 @@ 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);
+ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
@@ -2048,6 +2201,59 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
}
}
+static void acpi_device_dep_initialize(struct acpi_device *adev)
+{
+ struct acpi_dep_data *dep;
+ struct acpi_handle_list dep_devices;
+ acpi_status status;
+ int i;
+
+ if (!acpi_has_method(adev->handle, "_DEP"))
+ return;
+
+ status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+ &dep_devices);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Failed to evaluate _DEP.\n");
+ return;
+ }
+
+ for (i = 0; i < dep_devices.count; i++) {
+ struct acpi_device_info *info;
+ int skip;
+
+ status = acpi_get_object_info(dep_devices.handles[i], &info);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Error reading device info\n");
+ continue;
+ }
+
+ /*
+ * Skip the dependency of Windows System Power
+ * Management Controller
+ */
+ skip = info->valid & ACPI_VALID_HID &&
+ !strcmp(info->hardware_id.string, "INT3396");
+
+ kfree(info);
+
+ if (skip)
+ continue;
+
+ dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL);
+ if (!dep)
+ return;
+
+ dep->master = dep_devices.handles[i];
+ dep->slave = adev->handle;
+ adev->dep_unmet++;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_add_tail(&dep->node , &acpi_dep_list);
+ mutex_unlock(&acpi_dep_list_lock);
+ }
+}
+
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **return_value)
{
@@ -2074,6 +2280,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_CTRL_DEPTH;
acpi_scan_init_hotplug(device);
+ acpi_device_dep_initialize(device);
out:
if (!*return_value)
@@ -2194,6 +2401,29 @@ static void acpi_bus_attach(struct acpi_device *device)
device->handler->hotplug.notify_online(device);
}
+void acpi_walk_dep_device_list(acpi_handle handle)
+{
+ struct acpi_dep_data *dep, *tmp;
+ struct acpi_device *adev;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
+ if (dep->master == handle) {
+ acpi_bus_get_device(dep->slave, &adev);
+ if (!adev)
+ continue;
+
+ adev->dep_unmet--;
+ if (!adev->dep_unmet)
+ acpi_bus_attach(adev);
+ list_del(&dep->node);
+ kfree(dep);
+ }
+ }
+ mutex_unlock(&acpi_dep_list_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
+
/**
* acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
* @handle: Root of the namespace scope to scan.
@@ -2315,6 +2545,7 @@ int __init acpi_scan_init(void)
acpi_container_init();
acpi_memory_hotplug_init();
acpi_pnp_init();
+ acpi_int340x_thermal_init();
mutex_lock(&acpi_scan_lock);
/*
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 05a31b573fc3..8aa9254a387f 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -630,6 +630,7 @@ static int acpi_freeze_begin(void)
static int acpi_freeze_prepare(void)
{
acpi_enable_all_wakeup_gpes();
+ acpi_os_wait_events_complete();
enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
return 0;
}
@@ -825,6 +826,7 @@ static void acpi_power_off_prepare(void)
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
acpi_disable_all_gpes();
+ acpi_os_wait_events_complete();
}
static void acpi_power_off(void)
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 38cb9782d4b8..13e577c80201 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -537,7 +537,7 @@ static ssize_t counter_show(struct kobject *kobj,
if (result)
goto end;
- if (!(status & ACPI_EVENT_FLAG_HANDLE))
+ if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER))
size += sprintf(buf + size, " invalid");
else if (status & ACPI_EVENT_FLAG_ENABLED)
size += sprintf(buf + size, " enabled");
@@ -581,7 +581,7 @@ static ssize_t counter_set(struct kobject *kobj,
if (result)
goto end;
- if (!(status & ACPI_EVENT_FLAG_HANDLE)) {
+ if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) {
printk(KERN_WARNING PREFIX
"Can not change Invalid GPE/Fixed Event status\n");
return -EINVAL;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 6d5a6cda0734..93b81523a2fe 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -190,30 +190,24 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
}
-
int __init
-acpi_table_parse_entries(char *id,
- unsigned long table_size,
- int entry_id,
- acpi_tbl_entry_handler handler,
- unsigned int max_entries)
+acpi_parse_entries(char *id, unsigned long table_size,
+ acpi_tbl_entry_handler handler,
+ struct acpi_table_header *table_header,
+ int entry_id, unsigned int max_entries)
{
- struct acpi_table_header *table_header = NULL;
struct acpi_subtable_header *entry;
- unsigned int count = 0;
+ int count = 0;
unsigned long table_end;
- acpi_size tbl_size;
if (acpi_disabled)
return -ENODEV;
- if (!handler)
+ if (!id || !handler)
return -EINVAL;
- if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
- acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
- else
- acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
+ if (!table_size)
+ return -EINVAL;
if (!table_header) {
pr_warn("%4.4s not present\n", id);
@@ -230,9 +224,12 @@ acpi_table_parse_entries(char *id,
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
table_end) {
if (entry->type == entry_id
- && (!max_entries || count++ < max_entries))
+ && (!max_entries || count < max_entries)) {
if (handler(entry, table_end))
- goto err;
+ return -EINVAL;
+
+ count++;
+ }
/*
* If entry->length is 0, break from this loop to avoid
@@ -240,22 +237,53 @@ acpi_table_parse_entries(char *id,
*/
if (entry->length == 0) {
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
- goto err;
+ return -EINVAL;
}
entry = (struct acpi_subtable_header *)
((unsigned long)entry + entry->length);
}
+
if (max_entries && count > max_entries) {
pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
id, entry_id, count - max_entries, count);
}
- early_acpi_os_unmap_memory((char *)table_header, tbl_size);
return count;
-err:
+}
+
+int __init
+acpi_table_parse_entries(char *id,
+ unsigned long table_size,
+ int entry_id,
+ acpi_tbl_entry_handler handler,
+ unsigned int max_entries)
+{
+ struct acpi_table_header *table_header = NULL;
+ acpi_size tbl_size;
+ int count;
+ u32 instance = 0;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!id || !handler)
+ return -EINVAL;
+
+ if (!strncmp(id, ACPI_SIG_MADT, 4))
+ instance = acpi_apic_instance;
+
+ acpi_get_table_with_size(id, instance, &table_header, &tbl_size);
+ if (!table_header) {
+ pr_warn("%4.4s not present\n", id);
+ return -ENODEV;
+ }
+
+ count = acpi_parse_entries(id, table_size, handler, table_header,
+ entry_id, max_entries);
+
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
- return -EINVAL;
+ return count;
}
int __init
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 112817e963e0..d24fa1964eb8 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -528,7 +528,6 @@ static void acpi_thermal_check(void *data)
}
/* sys I/F for generic thermal sysfs support */
-#define KELVIN_TO_MILLICELSIUS(t, off) (((t) - (off)) * 100)
static int thermal_get_temp(struct thermal_zone_device *thermal,
unsigned long *temp)
@@ -543,7 +542,8 @@ static int thermal_get_temp(struct thermal_zone_device *thermal,
if (result)
return result;
- *temp = KELVIN_TO_MILLICELSIUS(tz->temperature, tz->kelvin_offset);
+ *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(tz->temperature,
+ tz->kelvin_offset);
return 0;
}
@@ -647,7 +647,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if (tz->trips.critical.flags.valid) {
if (!trip) {
- *temp = KELVIN_TO_MILLICELSIUS(
+ *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
tz->trips.critical.temperature,
tz->kelvin_offset);
return 0;
@@ -657,7 +657,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if (tz->trips.hot.flags.valid) {
if (!trip) {
- *temp = KELVIN_TO_MILLICELSIUS(
+ *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
tz->trips.hot.temperature,
tz->kelvin_offset);
return 0;
@@ -667,7 +667,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if (tz->trips.passive.flags.valid) {
if (!trip) {
- *temp = KELVIN_TO_MILLICELSIUS(
+ *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
tz->trips.passive.temperature,
tz->kelvin_offset);
return 0;
@@ -678,7 +678,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
if (!trip) {
- *temp = KELVIN_TO_MILLICELSIUS(
+ *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
tz->trips.active[i].temperature,
tz->kelvin_offset);
return 0;
@@ -694,7 +694,7 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
struct acpi_thermal *tz = thermal->devdata;
if (tz->trips.critical.flags.valid) {
- *temperature = KELVIN_TO_MILLICELSIUS(
+ *temperature = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
tz->trips.critical.temperature,
tz->kelvin_offset);
return 0;
@@ -714,8 +714,8 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
if (type == THERMAL_TRIP_ACTIVE) {
unsigned long trip_temp;
- unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature,
- tz->kelvin_offset);
+ unsigned long temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
+ tz->temperature, tz->kelvin_offset);
if (thermal_get_trip_temp(thermal, trip, &trip_temp))
return -EINVAL;
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 834f35c4bf8d..dd8ff63ee2b4 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -136,8 +136,7 @@ acpi_extract_package(union acpi_object *package,
break;
case 'B':
size_required +=
- sizeof(u8 *) +
- (element->buffer.length * sizeof(u8));
+ sizeof(u8 *) + element->buffer.length;
tail_offset += sizeof(u8 *);
break;
default:
@@ -149,6 +148,21 @@ acpi_extract_package(union acpi_object *package,
break;
}
break;
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ switch (format_string[i]) {
+ case 'R':
+ size_required += sizeof(void *);
+ tail_offset += sizeof(void *);
+ break;
+ default:
+ printk(KERN_WARNING PREFIX "Invalid package element"
+ " [%d] got reference,"
+ " expecting [%c]\n",
+ i, format_string[i]);
+ return AE_BAD_DATA;
+ break;
+ }
+ break;
case ACPI_TYPE_PACKAGE:
default:
@@ -240,14 +254,25 @@ acpi_extract_package(union acpi_object *package,
memcpy(tail, element->buffer.pointer,
element->buffer.length);
head += sizeof(u8 *);
- tail += element->buffer.length * sizeof(u8);
+ tail += element->buffer.length;
+ break;
+ default:
+ /* Should never get here */
+ break;
+ }
+ break;
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ switch (format_string[i]) {
+ case 'R':
+ *(void **)head =
+ (void *)element->reference.handle;
+ head += sizeof(void *);
break;
default:
/* Should never get here */
break;
}
break;
-
case ACPI_TYPE_PACKAGE:
/* TBD: handle nested packages... */
default:
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 807a88a0f394..185a57d13723 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1164,7 +1164,8 @@ static bool acpi_video_device_in_dod(struct acpi_video_device *device)
return true;
for (i = 0; i < video->attached_count; i++) {
- if (video->attached_array[i].bind_info == device)
+ if ((video->attached_array[i].value.int_val & 0xfff) ==
+ (device->device_id & 0xfff))
return true;
}
@@ -1680,6 +1681,19 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
printk(KERN_ERR PREFIX "Create sysfs link\n");
}
+static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
+{
+ struct acpi_video_device *dev;
+ union acpi_object *levels;
+
+ mutex_lock(&video->device_list_lock);
+ list_for_each_entry(dev, &video->video_device_list, entry) {
+ if (!acpi_video_device_lcd_query_levels(dev, &levels))
+ kfree(levels);
+ }
+ mutex_unlock(&video->device_list_lock);
+}
+
static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
{
struct acpi_video_device *dev;
@@ -1687,6 +1701,8 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
if (video->backlight_registered)
return 0;
+ acpi_video_run_bcl_for_osi(video);
+
if (!acpi_video_verify_backlight_support())
return 0;