aboutsummaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig1
-rw-r--r--drivers/acpi/asus_acpi.c55
-rw-r--r--drivers/acpi/battery.c5
-rw-r--r--drivers/acpi/bay.c6
-rw-r--r--drivers/acpi/blacklist.c58
-rw-r--r--drivers/acpi/bus.c25
-rw-r--r--drivers/acpi/debug.c57
-rw-r--r--drivers/acpi/dock.c6
-rw-r--r--drivers/acpi/ec.c19
-rw-r--r--drivers/acpi/events/evevent.c2
-rw-r--r--drivers/acpi/events/evgpe.c27
-rw-r--r--drivers/acpi/fan.c92
-rw-r--r--drivers/acpi/hardware/hwsleep.c2
-rw-r--r--drivers/acpi/namespace/nsxfeval.c10
-rw-r--r--drivers/acpi/osl.c81
-rw-r--r--drivers/acpi/pci_irq.c5
-rw-r--r--drivers/acpi/power.c6
-rw-r--r--drivers/acpi/processor_core.c40
-rw-r--r--drivers/acpi/processor_idle.c65
-rw-r--r--drivers/acpi/processor_perflib.c16
-rw-r--r--drivers/acpi/processor_thermal.c134
-rw-r--r--drivers/acpi/scan.c100
-rw-r--r--drivers/acpi/sleep/main.c17
-rw-r--r--drivers/acpi/sleep/proc.c46
-rw-r--r--drivers/acpi/system.c208
-rw-r--r--drivers/acpi/tables/Makefile2
-rw-r--r--drivers/acpi/tables/tbxfroot.c4
-rw-r--r--drivers/acpi/thermal.c663
-rw-r--r--drivers/acpi/utilities/utglobal.c2
-rw-r--r--drivers/acpi/video.c127
30 files changed, 1516 insertions, 365 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index f60cf6fea2b..0065f379457 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -186,6 +186,7 @@ config ACPI_HOTPLUG_CPU
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
+ select THERMAL
default y
help
This driver adds support for ACPI thermal zones. Most mobile and
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index d915fec9bf6..d25ef961415 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -142,6 +142,7 @@ struct asus_hotk {
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
A4S, //Z81sp
//(Centrino)
+ F3Sa,
END_MODEL
} model; //Models currently supported
u16 event_count[128]; //count for each event TODO make this better
@@ -405,7 +406,20 @@ static struct model_data model_conf[END_MODEL] = {
.brightness_get = "GPLV",
.mt_bt_switch = "BLED",
.mt_wled = "WLED"
- }
+ },
+
+ {
+ .name = "F3Sa",
+ .mt_bt_switch = "BLED",
+ .mt_wled = "WLED",
+ .mt_mled = "MLED",
+ .brightness_get = "GPLV",
+ .brightness_set = "SPLV",
+ .mt_lcd_switch = "\\_SB.PCI0.SBRG.EC0._Q10",
+ .lcd_status = "\\_SB.PCI0.SBRG.EC0.RPIN",
+ .display_get = "\\ADVG",
+ .display_set = "SDSP",
+ },
};
@@ -710,15 +724,8 @@ static int get_lcd_state(void)
{
int lcd = 0;
- if (hotk->model != L3H) {
- /* We don't have to check anything if we are here */
- if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
- printk(KERN_WARNING
- "Asus ACPI: Error reading LCD status\n");
-
- if (hotk->model == L2D)
- lcd = ~lcd;
- } else { /* L3H and the like have to be handled differently */
+ if (hotk->model == L3H) {
+ /* L3H and the like have to be handled differently */
acpi_status status = 0;
struct acpi_object_list input;
union acpi_object mt_params[2];
@@ -745,6 +752,32 @@ static int get_lcd_state(void)
if (out_obj.type == ACPI_TYPE_INTEGER)
/* That's what the AML code does */
lcd = out_obj.integer.value >> 8;
+ } else if (hotk->model == F3Sa) {
+ unsigned long tmp;
+ union acpi_object param;
+ struct acpi_object_list input;
+ acpi_status status;
+
+ /* Read pin 11 */
+ param.type = ACPI_TYPE_INTEGER;
+ param.integer.value = 0x11;
+ input.count = 1;
+ input.pointer = &param;
+
+ status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
+ &input, &tmp);
+ if (status != AE_OK)
+ return -1;
+
+ lcd = tmp;
+ } else {
+ /* We don't have to check anything if we are here */
+ if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
+ printk(KERN_WARNING
+ "Asus ACPI: Error reading LCD status\n");
+
+ if (hotk->model == L2D)
+ lcd = ~lcd;
}
return (lcd & 1);
@@ -1134,6 +1167,8 @@ static int asus_model_match(char *model)
return W5A;
else if (strncmp(model, "A4S", 3) == 0)
return A4S;
+ else if (strncmp(model, "F3Sa", 4) == 0)
+ return F3Sa;
else
return END_MODEL;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index c4a769d1ba8..f6215e80980 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -194,6 +194,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = battery->oem_info;
break;
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ val->strval = battery->serial_number;
+ break;
default:
return -EINVAL;
}
@@ -212,6 +215,7 @@ static enum power_supply_property charge_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static enum power_supply_property energy_battery_props[] = {
@@ -226,6 +230,7 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
#endif
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 6daf6088ac8..477711435b2 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -46,6 +46,12 @@ MODULE_LICENSE("GPL");
printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
static void bay_notify(acpi_handle handle, u32 event, void *data);
+static const struct acpi_device_id bay_device_ids[] = {
+ {"LNXIOBAY", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, bay_device_ids);
+
struct bay {
acpi_handle handle;
char *name;
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 8809654d6cc..6dbaa2d15fe 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -70,8 +70,6 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
/* IBM 600E - _ADR should return 7, but it returns 1 */
{"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1},
- {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
- "Bogus PCI routing", 1},
{""}
};
@@ -208,33 +206,35 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* Disable OSI(Linux) warnings on all "Acer, inc."
*
* _OSI(Linux) disables the latest Windows BIOS code:
+ * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
+ * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
* _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
*/
- {
- .callback = dmi_disable_osi_linux,
- .ident = "Acer, inc.",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
- },
- },
+ /*
+ * note that dmi_check_system() uses strstr()
+ * to match sub-strings rather than !strcmp(),
+ * so "Acer" below matches "Acer, inc." above.
+ */
/*
* Disable OSI(Linux) warnings on all "Acer"
*
* _OSI(Linux) effect unknown:
- * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
+ *
+ * _OSI(Linux) is a NOP:
+ * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
*/
{
- .callback = dmi_unknown_osi_linux,
+ .callback = dmi_disable_osi_linux,
.ident = "Acer",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -242,21 +242,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
/*
* Disable OSI(Linux) warnings on all "Apple Computer, Inc."
+ * Disable OSI(Linux) warnings on all "Apple Inc."
*
* _OSI(Linux) confirmed to be a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+ * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
* _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
- * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
*/
{
.callback = dmi_disable_osi_linux,
.ident = "Apple",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
},
},
/*
@@ -294,13 +295,13 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
*/
{
- .callback = dmi_unknown_osi_linux,
+ .callback = dmi_disable_osi_linux,
.ident = "Compal",
.matches = {
DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
},
},
- { /* OSI(Linux) touches USB, breaks suspend to disk */
+ { /* OSI(Linux) touches USB, unknown side-effect */
.callback = dmi_disable_osi_linux,
.ident = "Dell Dimension 5150",
.matches = {
@@ -310,7 +311,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{ /* OSI(Linux) is a NOP */
.callback = dmi_disable_osi_linux,
- .ident = "Dell",
+ .ident = "Dell i1501",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
@@ -318,7 +319,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell Latitude D830",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
@@ -326,7 +327,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell OP GX620",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
@@ -334,15 +335,23 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell PE 1900",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
},
},
+ { /* OSI(Linux) is a NOP */
+ .callback = dmi_disable_osi_linux,
+ .ident = "Dell PE R200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R200"),
+ },
+ },
{ /* OSI(Linux) touches USB */
.callback = dmi_disable_osi_linux,
- .ident = "Dell",
+ .ident = "Dell PR 390",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
@@ -358,7 +367,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell PE SC440",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
@@ -474,6 +483,11 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
*
* _OSI(Linux) confirmed to be a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
+ * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
+ *
+ * unknown:
+ * DMI_MATCH(DMI_PRODUCT_NAME, "S1-MDGDG"),
+ * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
*/
{
.callback = dmi_disable_osi_linux,
@@ -516,7 +530,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
*/
{
- .callback = dmi_unknown_osi_linux,
+ .callback = dmi_disable_osi_linux,
.ident = "Sony",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 1b4cf984b08..8df325dafe0 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device)
EXPORT_SYMBOL(acpi_bus_get_status);
+void acpi_bus_private_data_handler(acpi_handle handle,
+ u32 function, void *context)
+{
+ return;
+}
+EXPORT_SYMBOL(acpi_bus_private_data_handler);
+
+int acpi_bus_get_private_data(acpi_handle handle, void **data)
+{
+ acpi_status status = AE_OK;
+
+ if (!*data)
+ return -EINVAL;
+
+ status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
+ if (ACPI_FAILURE(status) || !*data) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+ handle));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(acpi_bus_get_private_data);
+
/* --------------------------------------------------------------------------
Power Management
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index bf513e07b77..6df564f4ca6 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -130,6 +130,63 @@ static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+static char trace_method_name[6];
+module_param_string(trace_method_name, trace_method_name, 6, 0644);
+static unsigned int trace_debug_layer;
+module_param(trace_debug_layer, uint, 0644);
+static unsigned int trace_debug_level;
+module_param(trace_debug_level, uint, 0644);
+
+static int param_set_trace_state(const char *val, struct kernel_param *kp)
+{
+ int result = 0;
+
+ if (!strncmp(val, "enable", strlen("enable") - 1)) {
+ result = acpi_debug_trace(trace_method_name, trace_debug_level,
+ trace_debug_layer, 0);
+ if (result)
+ result = -EBUSY;
+ goto exit;
+ }
+
+ if (!strncmp(val, "disable", strlen("disable") - 1)) {
+ int name = 0;
+ result = acpi_debug_trace((char *)&name, trace_debug_level,
+ trace_debug_layer, 0);
+ if (result)
+ result = -EBUSY;
+ goto exit;
+ }
+
+ if (!strncmp(val, "1", 1)) {
+ result = acpi_debug_trace(trace_method_name, trace_debug_level,
+ trace_debug_layer, 1);
+ if (result)
+ result = -EBUSY;
+ goto exit;
+ }
+
+ result = -EINVAL;
+exit:
+ return result;
+}
+
+static int param_get_trace_state(char *buffer, struct kernel_param *kp)
+{
+ if (!acpi_gbl_trace_method_name)
+ return sprintf(buffer, "disable");
+ else {
+ if (acpi_gbl_trace_flags & 1)
+ return sprintf(buffer, "1");
+ else
+ return sprintf(buffer, "enable");
+ }
+ return 0;
+}
+
+module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
+ NULL, 0644);
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 1dabdf4c07b..b3dec2101e2 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -51,6 +51,12 @@ static struct atomic_notifier_head dock_notifier_list;
static struct platform_device *dock_device;
static char dock_device_name[] = "dock";
+static const struct acpi_device_id dock_device_ids[] = {
+ {"LNXDOCK", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, dock_device_ids);
+
struct dock_station {
acpi_handle handle;
unsigned long last_dock_time;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 987b967c746..7222a18a031 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -573,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
void *handler_context, void *region_context)
{
struct acpi_ec *ec = handler_context;
- int result = 0, i = 0;
+ int result = 0, i;
u8 temp = 0;
if ((address > 0xFF) || !value || !handler_context)
@@ -585,7 +585,18 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (bits != 8 && acpi_strict)
return AE_BAD_PARAMETER;
- while (bits - i > 0) {
+ acpi_ec_burst_enable(ec);
+
+ if (function == ACPI_READ) {
+ result = acpi_ec_read(ec, address, &temp);
+ *value = temp;
+ } else {
+ temp = 0xff & (*value);
+ result = acpi_ec_write(ec, address, temp);
+ }
+
+ for (i = 8; unlikely(bits - i > 0); i += 8) {
+ ++address;
if (function == ACPI_READ) {
result = acpi_ec_read(ec, address, &temp);
(*value) |= ((acpi_integer)temp) << i;
@@ -593,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
temp = 0xff & ((*value) >> i);
result = acpi_ec_write(ec, address, temp);
}
- i += 8;
- ++address;
}
+ acpi_ec_burst_disable(ec);
+
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index e41287815ea..3048801a37b 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -259,7 +259,7 @@ u32 acpi_ev_fixed_event_detect(void)
enable_bit_mask)) {
/* Found an active (signalled) event */
-
+ acpi_os_fixed_event_count(i);
int_status |= acpi_ev_fixed_event_dispatch((u32) i);
}
}
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index e22f4a973c0..0dadd2adc80 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -270,18 +270,18 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
case ACPI_GPE_TYPE_WAKE_RUN:
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
- /*lint -fallthrough */
+ /* fallthrough */
case ACPI_GPE_TYPE_RUNTIME:
/* Disable the requested runtime GPE */
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
- status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
- break;
+
+ /* fallthrough */
default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ acpi_hw_write_gpe_enable_reg(gpe_event_info);
}
return_ACPI_STATUS(AE_OK);
@@ -501,6 +501,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* an interrupt handler.
*
******************************************************************************/
+static void acpi_ev_asynch_enable_gpe(void *context);
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
@@ -576,22 +577,30 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
method_node)));
}
}
+ /* Defer enabling of GPE until all notify handlers are done */
+ acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
+ gpe_event_info);
+ return_VOID;
+}
- if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+static void acpi_ev_asynch_enable_gpe(void *context)
+{
+ struct acpi_gpe_event_info *gpe_event_info = context;
+ acpi_status status;
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
ACPI_GPE_LEVEL_TRIGGERED) {
/*
* GPE is level-triggered, we clear the GPE status bit after
* handling the event.
*/
- status = acpi_hw_clear_gpe(&local_gpe_event_info);
+ status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
return_VOID;
}
}
/* Enable this GPE */
-
- (void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
+ (void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
return_VOID;
}
@@ -618,7 +627,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
- acpi_gpe_count++;
+ acpi_os_gpe_count(gpe_number);
/*
* If edge-triggered, clear the GPE status bit now. Note that
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index a6e149d692c..48cb705b274 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -30,7 +30,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
-
+#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = {
},
};
+/* thermal cooling device callbacks */
+static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+ /* ACPI fan device only support two states: ON/OFF */
+ return sprintf(buf, "1\n");
+}
+
+static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+ struct acpi_device *device = cdev->devdata;
+ int state;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ result = acpi_bus_get_power(device->handle, &state);
+ if (result)
+ return result;
+
+ return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
+ (state == ACPI_STATE_D0 ? "1" : "unknown"));
+}
+
+static int
+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+ struct acpi_device *device = cdev->devdata;
+ int result;
+
+ if (!device || (state != 0 && state != 1))
+ return -EINVAL;
+
+ result = acpi_bus_set_power(device->handle,
+ state ? ACPI_STATE_D0 : ACPI_STATE_D3);
+
+ return result;
+}
+
+static struct thermal_cooling_device_ops fan_cooling_ops = {
+ .get_max_state = fan_get_max_state,
+ .get_cur_state = fan_get_cur_state,
+ .set_cur_state = fan_set_cur_state,
+};
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_fan_dir;
@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
return 0;
}
+#else
+static int acpi_fan_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static int acpi_fan_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+#endif
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
static int acpi_fan_add(struct acpi_device *device)
{
int result = 0;
- struct acpi_fan *fan = NULL;
int state = 0;
-
+ struct thermal_cooling_device *cdev;
if (!device)
return -EINVAL;
@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device)
acpi_bus_set_power(device->handle, state);
device->flags.force_power_state = 0;
+ cdev = thermal_cooling_device_register("Fan", device,
+ &fan_cooling_ops);
+ if (cdev)
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, cdev->id);
+ else
+ goto end;
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ return result;
+
+ result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
+ "device");
+ if (result)
+ return result;
+
result = acpi_fan_add_fs(device);
if (result)
goto end;
@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device)
!device->power.state ? "on" : "off");
end:
- if (result)
- kfree(fan);
-
return result;
}
static int acpi_fan_remove(struct acpi_device *device, int type)
{
- if (!device || !acpi_driver_data(device))
+ struct thermal_cooling_device *cdev = acpi_driver_data(device);
+
+ if (!device || !cdev)
return -EINVAL;
acpi_fan_remove_fs(device);
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ sysfs_remove_link(&cdev->device.kobj, "device");
+ thermal_cooling_device_unregister(cdev);
return 0;
}
@@ -261,10 +337,12 @@ static int __init acpi_fan_init(void)
int result = 0;
+#ifdef CONFIG_ACPI_PROCFS
acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
if (!acpi_fan_dir)
return -ENODEV;
acpi_fan_dir->owner = THIS_MODULE;
+#endif
result = acpi_bus_register_driver(&acpi_fan_driver);
if (result < 0) {
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index fd1c4ba6336..058d0be5cbe 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -286,13 +286,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
}
/*
+ * 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs
*/
status = acpi_hw_disable_all_gpes();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
acpi_gbl_system_awake_and_running = FALSE;
status = acpi_hw_enable_all_wakeup_gpes();
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index f39fbc6b923..b92133faf5b 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -443,6 +443,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
struct acpica_device_id hid;
struct acpi_compatible_id_list *cid;
acpi_native_uint i;
+ int found;
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -496,16 +497,19 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
/* Walk the CID list */
+ found = 0;
for (i = 0; i < cid->count; i++) {
if (ACPI_STRNCMP(cid->id[i].value, info->hid,
sizeof(struct
- acpi_compatible_id)) !=
+ acpi_compatible_id)) ==
0) {
- ACPI_FREE(cid);
- return (AE_OK);
+ found = 1;
+ break;
}
}
ACPI_FREE(cid);
+ if (!found)
+ return (AE_OK);
}
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e53fb516f9d..3b8aef3aefe 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -120,7 +120,7 @@ static char osi_additional_string[OSI_STRING_LENGTH_MAX];
*/
#define OSI_LINUX_ENABLE 0
-struct osi_linux {
+static struct osi_linux {
unsigned int enable:1;
unsigned int dmi:1;
unsigned int cmdline:1;
@@ -250,11 +250,16 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
"System description tables not found\n");
return 0;
}
- } else
- return acpi_find_rsdp();
+ } else {
+ acpi_physical_address pa = 0;
+
+ acpi_find_root_pointer(&pa);
+ return pa;
+ }
}
-void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+void __iomem *__init_refok
+acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -332,7 +337,15 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
static irqreturn_t acpi_irq(int irq, void *dev_id)
{
- return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+ u32 handled;
+
+ handled = (*acpi_irq_handler) (acpi_irq_context);
+
+ if (handled) {
+ acpi_irq_handled++;
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
}
acpi_status
@@ -341,6 +354,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
{
unsigned int irq;
+ acpi_irq_stats_init();
+
/*
* Ignore the GSI from the core, and use the value in our copy of the
* FADT. It may not be the same if an interrupt source override exists
@@ -661,25 +676,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
dpc->function(dpc->context);
kfree(dpc);
- /* Yield cpu to notify thread */
- cond_resched();
-
- return;
-}
-
-static void acpi_os_execute_notify(struct work_struct *work)
-{
- struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
-
- if (!dpc) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- dpc->function(dpc->context);
-
- kfree(dpc);
-
return;
}
@@ -703,7 +699,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
{
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
-
+ struct workqueue_struct *queue;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
function, context));
@@ -727,20 +723,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
dpc->function = function;
dpc->context = context;
- if (type == OSL_NOTIFY_HANDLER) {
- INIT_WORK(&dpc->work, acpi_os_execute_notify);
- if (!queue_work(kacpi_notify_wq, &dpc->work)) {
- status = AE_ERROR;
- kfree(dpc);
- }
- } else {
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- if (!queue_work(kacpid_wq, &dpc->work)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Call to queue_work() failed.\n"));
- status = AE_ERROR;
- kfree(dpc);
- }
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+ queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
+ if (!queue_work(queue, &dpc->work)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Call to queue_work() failed.\n"));
+ status = AE_ERROR;
+ kfree(dpc);
}
return_ACPI_STATUS(status);
}
@@ -1213,24 +1202,24 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
*
* Returns 0 on success
*/
-int acpi_dmi_dump(void)
+static int acpi_dmi_dump(void)
{
if (!dmi_available)
return -1;
printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
- dmi_get_slot(DMI_SYS_VENDOR));
+ dmi_get_system_info(DMI_SYS_VENDOR));
printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
- dmi_get_slot(DMI_PRODUCT_NAME));
+ dmi_get_system_info(DMI_PRODUCT_NAME));
printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
- dmi_get_slot(DMI_PRODUCT_VERSION));
+ dmi_get_system_info(DMI_PRODUCT_VERSION));
printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
- dmi_get_slot(DMI_BOARD_NAME));
+ dmi_get_system_info(DMI_BOARD_NAME));
printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
- dmi_get_slot(DMI_BIOS_VENDOR));
+ dmi_get_system_info(DMI_BIOS_VENDOR));
printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
- dmi_get_slot(DMI_BIOS_DATE));
+ dmi_get_system_info(DMI_BIOS_DATE));
return 0;
}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 62010c2481b..76d9c669d2d 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -51,10 +51,8 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
int bus,
int device, int pin)
{
- struct list_head *node = NULL;
struct acpi_prt_entry *entry = NULL;
-
if (!acpi_prt.count)
return NULL;
@@ -64,8 +62,7 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
*
*/
spin_lock(&acpi_prt_lock);
- list_for_each(node, &acpi_prt.entries) {
- entry = list_entry(node, struct acpi_prt_entry, node);
+ list_for_each_entry(entry, &acpi_prt.entries, node) {
if ((segment == entry->id.segment)
&& (bus == entry->id.bus)
&& (device == entry->id.device)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index af1769a20c7..76bf6d90c70 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -458,11 +458,9 @@ int acpi_power_transition(struct acpi_device *device, int state)
}
end:
- if (result) {
+ if (result)
device->power.state = ACPI_STATE_UNKNOWN;
- printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n",
- device->pnp.bus_id, state);
- } else {
+ else {
/* We shouldn't change the state till all above operations succeed */
device->power.state = state;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e48ee4f8749..315fd8f7e8a 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -668,6 +668,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
acpi_processor_power_init(pr, device);
+ pr->cdev = thermal_cooling_device_register("Processor", device,
+ &processor_cooling_ops);
+ if (pr->cdev)
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, pr->cdev->id);
+ else
+ goto end;
+
+ result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ return result;
+ result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
+ "device");
+ if (result)
+ return result;
+
if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports",
acpi_device_name(device), acpi_device_bid(device));
@@ -791,6 +809,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
acpi_processor_remove_fs(device);
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ thermal_cooling_device_unregister(pr->cdev);
+ pr->cdev = NULL;
+
processors[pr->id] = NULL;
kfree(pr);
@@ -812,11 +835,18 @@ static int is_processor_present(acpi_handle handle)
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
- ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
- return 0;
- }
- return 1;
+ /*
+ * if a processor object does not have an _STA object,
+ * OSPM assumes that the processor is present.
+ */
+ if (status == AE_NOT_FOUND)
+ return 1;
+
+ if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
+ return 1;
+
+ ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
+ return 0;
}
static
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index eb1f82f7915..32003fdc91e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -38,7 +38,7 @@
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> /* need_resched() */
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
@@ -98,6 +98,9 @@ module_param(bm_history, uint, 0644);
static int acpi_processor_set_power_policy(struct acpi_processor *pr);
+#else /* CONFIG_CPU_IDLE */
+static unsigned int latency_factor __read_mostly = 2;
+module_param(latency_factor, uint, 0644);
#endif
/*
@@ -201,6 +204,10 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
}
+/*
+ * Callers should disable interrupts before the call and enable
+ * interrupts after return.
+ */
static void acpi_safe_halt(void)
{
current_thread_info()->status &= ~TS_POLLING;
@@ -261,7 +268,7 @@ static atomic_t c3_cpu_count;
/* Common C-state entry for C2, C3, .. */
static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
{
- if (cstate->space_id == ACPI_CSTATE_FFH) {
+ if (cstate->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cstate);
} else {
@@ -413,6 +420,8 @@ static void acpi_processor_idle(void)
pm_idle_save();
else
acpi_safe_halt();
+
+ local_irq_enable();
return;
}
@@ -521,6 +530,7 @@ static void acpi_processor_idle(void)
* skew otherwise.
*/
sleep_ticks = 0xFFFFFFFF;
+ local_irq_enable();
break;
case ACPI_STATE_C2:
@@ -648,7 +658,8 @@ static void acpi_processor_idle(void)
if (cx->promotion.state &&
((cx->promotion.state - pr->power.states) <= max_cstate)) {
if (sleep_ticks > cx->promotion.threshold.ticks &&
- cx->promotion.state->latency <= system_latency_constraint()) {
+ cx->promotion.state->latency <=
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
cx->promotion.count++;
cx->demotion.count = 0;
if (cx->promotion.count >=
@@ -692,7 +703,8 @@ static void acpi_processor_idle(void)
* or if the latency of the current state is unacceptable
*/
if ((pr->power.state - pr->power.states) > max_cstate ||
- pr->power.state->latency > system_latency_constraint()) {
+ pr->power.state->latency >
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
if (cx->demotion.state)
next_state = cx->demotion.state;
}
@@ -920,20 +932,20 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
cx.address = reg->address;
cx.index = current_count + 1;
- cx.space_id = ACPI_CSTATE_SYSTEMIO;
+ cx.entry_method = ACPI_CSTATE_SYSTEMIO;
if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
if (acpi_processor_ffh_cstate_probe
(pr->id, &cx, reg) == 0) {
- cx.space_id = ACPI_CSTATE_FFH;
- } else if (cx.type != ACPI_STATE_C1) {
+ cx.entry_method = ACPI_CSTATE_FFH;
+ } else if (cx.type == ACPI_STATE_C1) {
/*
* C1 is a special case where FIXED_HARDWARE
* can be handled in non-MWAIT way as well.
* In that case, save this _CST entry info.
- * That is, we retain space_id of SYSTEM_IO for
- * halt based C1.
* Otherwise, ignore this info and continue.
*/
+ cx.entry_method = ACPI_CSTATE_HALT;
+ } else {
continue;
}
}
@@ -1200,7 +1212,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
"maximum allowed latency: %d usec\n",
pr->power.state ? pr->power.state - pr->power.states : 0,
max_cstate, (unsigned)pr->power.bm_activity,
- system_latency_constraint());
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY));
seq_puts(seq, "states:\n");
@@ -1367,12 +1379,16 @@ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
/**
* acpi_idle_do_entry - a helper function that does C2 and C3 type entry
* @cx: cstate data
+ *
+ * Caller disables interrupt before call and enables interrupt after return.
*/
static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
- if (cx->space_id == ACPI_CSTATE_FFH) {
+ if (cx->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx);
+ } else if (cx->entry_method == ACPI_CSTATE_HALT) {
+ acpi_safe_halt();
} else {
int unused;
/* IO port based C-state */
@@ -1394,21 +1410,27 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
+ u32 t1, t2;
struct acpi_processor *pr;
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+
pr = processors[smp_processor_id()];
if (unlikely(!pr))
return 0;
+ local_irq_disable();
if (pr->flags.bm_check)
acpi_idle_update_bm_rld(pr, cx);
- acpi_safe_halt();
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ local_irq_enable();
cx->usage++;
- return 0;
+ return ticks_elapsed_in_us(t1, t2);
}
/**
@@ -1515,7 +1537,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (dev->safe_state) {
return dev->safe_state->enter(dev, dev->safe_state);
} else {
+ local_irq_disable();
acpi_safe_halt();
+ local_irq_enable();
return 0;
}
}
@@ -1607,7 +1631,7 @@ struct cpuidle_driver acpi_idle_driver = {
*/
static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
{
- int i, count = 0;
+ int i, count = CPUIDLE_DRIVER_STATE_START;
struct acpi_processor_cx *cx;
struct cpuidle_state *state;
struct cpuidle_device *dev = &pr->power.dev;
@@ -1636,13 +1660,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
state->exit_latency = cx->latency;
- state->target_residency = cx->latency * 6;
+ state->target_residency = cx->latency * latency_factor;
state->power_usage = cx->power;
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
state->flags |= CPUIDLE_FLAG_SHALLOW;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_c1;
dev->safe_state = state;
break;
@@ -1665,6 +1690,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
}
count++;
+ if (count == CPUIDLE_STATE_MAX)
+ break;
}
dev->state_count = count;
@@ -1718,8 +1745,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
"ACPI: processor limited to max C-state %d\n",
max_cstate);
first_run++;
-#if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP)
- register_latency_notifier(&acpi_processor_latency_notifier);
+#if !defined(CONFIG_CPU_IDLE) && defined(CONFIG_SMP)
+ pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
+ &acpi_processor_latency_notifier);
#endif
}
@@ -1806,7 +1834,8 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
*/
cpu_idle_wait();
#ifdef CONFIG_SMP
- unregister_latency_notifier(&acpi_processor_latency_notifier);
+ pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
+ &acpi_processor_latency_notifier);
#endif
}
#endif
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 463b0247cbc..f32010bee4d 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -60,6 +60,11 @@ static DEFINE_MUTEX(performance_mutex);
* policy is adjusted accordingly.
*/
+static unsigned int ignore_ppc = 0;
+module_param(ignore_ppc, uint, 0644);
+MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
+ "limited by BIOS, this should help");
+
#define PPC_REGISTERED 1
#define PPC_IN_USE 2
@@ -72,6 +77,9 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
struct acpi_processor *pr;
unsigned int ppc = 0;
+ if (ignore_ppc)
+ return 0;
+
mutex_lock(&performance_mutex);
if (event != CPUFREQ_INCOMPATIBLE)
@@ -130,7 +138,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
{
- int ret = acpi_processor_get_platform_limit(pr);
+ int ret;
+
+ if (ignore_ppc)
+ return 0;
+
+ ret = acpi_processor_get_platform_limit(pr);
+
if (ret < 0)
return (ret);
else
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 06e6f3fb882..9cb43f52f7b 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -32,6 +32,7 @@
#include <linux/cpufreq.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/sysdev.h>
#include <asm/uaccess.h>
@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
* _any_ cpufreq driver and not only the acpi-cpufreq driver.
*/
+#define CPUFREQ_THERMAL_MIN_STEP 0
+#define CPUFREQ_THERMAL_MAX_STEP 3
+
static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
static unsigned int acpi_thermal_cpufreq_is_init = 0;
@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu)
if (!cpu_has_cpufreq(cpu))
return -ENODEV;
- if (cpufreq_thermal_reduction_pctg[cpu] < 60) {
- cpufreq_thermal_reduction_pctg[cpu] += 20;
+ if (cpufreq_thermal_reduction_pctg[cpu] <
+ CPUFREQ_THERMAL_MAX_STEP) {
+ cpufreq_thermal_reduction_pctg[cpu]++;
cpufreq_update_policy(cpu);
return 0;
}
@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
if (!cpu_has_cpufreq(cpu))
return -ENODEV;
- if (cpufreq_thermal_reduction_pctg[cpu] > 20)
- cpufreq_thermal_reduction_pctg[cpu] -= 20;
+ if (cpufreq_thermal_reduction_pctg[cpu] >
+ (CPUFREQ_THERMAL_MIN_STEP + 1))
+ cpufreq_thermal_reduction_pctg[cpu]--;
else
cpufreq_thermal_reduction_pctg[cpu] = 0;
cpufreq_update_policy(cpu);
@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
max_freq =
(policy->cpuinfo.max_freq *
- (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100;
+ (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
cpufreq_verify_within_limits(policy, 0, max_freq);
@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
.notifier_call = acpi_thermal_cpufreq_notifier,
};
+static int cpufreq_get_max_state(unsigned int cpu)
+{
+ if (!cpu_has_cpufreq(cpu))
+ return 0;
+
+ return CPUFREQ_THERMAL_MAX_STEP;
+}
+
+static int cpufreq_get_cur_state(unsigned int cpu)
+{
+ if (!cpu_has_cpufreq(cpu))
+ return 0;
+
+ return cpufreq_thermal_reduction_pctg[cpu];
+}
+
+static int cpufreq_set_cur_state(unsigned int cpu, int state)
+{
+ if (!cpu_has_cpufreq(cpu))
+ return 0;
+
+ cpufreq_thermal_reduction_pctg[cpu] = state;
+ cpufreq_update_policy(cpu);
+ return 0;
+}
+
void acpi_thermal_cpufreq_init(void)
{
int i;
@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void)
}
#else /* ! CONFIG_CPU_FREQ */
+static int cpufreq_get_max_state(unsigned int cpu)
+{
+ return 0;
+}
+
+static int cpufreq_get_cur_state(unsigned int cpu)
+{
+ return 0;
+}
+
+static int cpufreq_set_cur_state(unsigned int cpu, int state)
+{
+ return 0;
+}
static int acpi_thermal_cpufreq_increase(unsigned int cpu)
{
@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
return 0;
}
+/* thermal coolign device callbacks */
+static int acpi_processor_max_state(struct acpi_processor *pr)
+{
+ int max_state = 0;
+
+ /*
+ * There exists four states according to
+ * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
+ */
+ max_state += cpufreq_get_max_state(pr->id);
+ if (pr->flags.throttling)
+ max_state += (pr->throttling.state_count -1);
+
+ return max_state;
+}
+static int
+processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_processor *pr = acpi_driver_data(device);
+
+ if (!device || !pr)
+ return -EINVAL;
+
+ return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
+}
+
+static int
+processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_processor *pr = acpi_driver_data(device);
+ int cur_state;
+
+ if (!device || !pr)
+ return -EINVAL;
+
+ cur_state = cpufreq_get_cur_state(pr->id);
+ if (pr->flags.throttling)
+ cur_state += pr->throttling.state;
+
+ return sprintf(buf, "%d\n", cur_state);
+}
+
+static int
+processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_processor *pr = acpi_driver_data(device);
+ int result = 0;
+ int max_pstate;
+
+ if (!device || !pr)
+ return -EINVAL;
+
+ max_pstate = cpufreq_get_max_state(pr->id);
+
+ if (state > acpi_processor_max_state(pr))
+ return -EINVAL;
+
+ if (state <= max_pstate) {
+ if (pr->flags.throttling && pr->throttling.state)
+ result = acpi_processor_set_throttling(pr, 0);
+ cpufreq_set_cur_state(pr->id, state);
+ } else {
+ cpufreq_set_cur_state(pr->id, max_pstate);
+ result = acpi_processor_set_throttling(pr,
+ state - max_pstate);
+ }
+ return result;
+}
+
+struct thermal_cooling_device_ops processor_cooling_ops = {
+ .get_max_state = processor_get_max_state,
+ .get_cur_state = processor_get_cur_state,
+ .set_cur_state = processor_set_cur_state,
+};
+
/* /proc interface */
static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index d9d531cce27..c7b0aa52dd2 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -941,6 +941,15 @@ static int acpi_bay_match(struct acpi_device *device){
return -ENODEV;
}
+/*
+ * acpi_dock_match - see if a device has a _DCK method
+ */
+static int acpi_dock_match(struct acpi_device *device)
+{
+ acpi_handle tmp;
+ return acpi_get_handle(device->handle, "_DCK", &tmp);
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
@@ -950,6 +959,7 @@ static void acpi_device_set_id(struct acpi_device *device,
char *hid = NULL;
char *uid = NULL;
struct acpi_compatible_id_list *cid_list = NULL;
+ const char *cid_add = NULL;
acpi_status status;
switch (type) {
@@ -972,15 +982,18 @@ static void acpi_device_set_id(struct acpi_device *device,
device->flags.bus_address = 1;
}
- if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
- status = acpi_video_bus_match(device);
- if(ACPI_SUCCESS(status))
- hid = ACPI_VIDEO_HID;
+ /* If we have a video/bay/dock device, add our selfdefined
+ HID to the CID list. Like that the video/bay/dock drivers
+ will get autoloaded and the device might still match
+ against another driver.
+ */
+ if (ACPI_SUCCESS(acpi_video_bus_match(device)))
+ cid_add = ACPI_VIDEO_HID;
+ else if (ACPI_SUCCESS(acpi_bay_match(device)))
+ cid_add = ACPI_BAY_HID;
+ else if (ACPI_SUCCESS(acpi_dock_match(device)))
+ cid_add = ACPI_DOCK_HID;
- status = acpi_bay_match(device);
- if (ACPI_SUCCESS(status))
- hid = ACPI_BAY_HID;
- }
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
@@ -1021,11 +1034,44 @@ static void acpi_device_set_id(struct acpi_device *device,
strcpy(device->pnp.unique_id, uid);
device->flags.unique_id = 1;
}
- if (cid_list) {
- device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
- if (device->pnp.cid_list)
- memcpy(device->pnp.cid_list, cid_list, cid_list->size);
- else
+ if (cid_list || cid_add) {
+ struct acpi_compatible_id_list *list;
+ int size = 0;
+ int count = 0;
+
+ if (cid_list) {
+ size = cid_list->size;
+ } else if (cid_add) {
+ size = sizeof(struct acpi_compatible_id_list);
+ cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
+ if (!cid_list) {
+ printk(KERN_ERR "Memory allocation error\n");
+ kfree(buffer.pointer);
+ return;
+ } else {
+ cid_list->count = 0;
+ cid_list->size = size;
+ }
+ }
+ if (cid_add)
+ size += sizeof(struct acpi_compatible_id);
+ list = kmalloc(size, GFP_KERNEL);
+
+ if (list) {
+ if (cid_list) {
+ memcpy(list, cid_list, cid_list->size);
+ count = cid_list->count;
+ }
+ if (cid_add) {
+ strncpy(list->id[count].value, cid_add,
+ ACPI_MAX_CID_LENGTH);
+ count++;
+ device->flags.compatible_ids = 1;
+ }
+ list->size = size;
+ list->count = count;
+ device->pnp.cid_list = list;
+ } else
printk(KERN_ERR "Memory allocation error\n");
}
@@ -1081,6 +1127,20 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
}
static int
+acpi_is_child_device(struct acpi_device *device,
+ int (*matcher)(struct acpi_device *))
+{
+ int result = -ENODEV;
+
+ do {
+ if (ACPI_SUCCESS(matcher(device)))
+ return AE_OK;
+ } while ((device = device->parent));
+
+ return result;
+}
+
+static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
@@ -1131,10 +1191,20 @@ acpi_add_single_object(struct acpi_device **child,
case ACPI_BUS_TYPE_PROCESSOR:
case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device);
- if (ACPI_FAILURE(result) || !device->status.present) {
- result = -ENOENT;
+ if (ACPI_FAILURE(result)) {
+ result = -ENODEV;
goto end;
}
+ if (!device->status.present) {
+ /* Bay and dock should be handled even if absent */
+ if (!ACPI_SUCCESS(
+ acpi_is_child_device(device, acpi_bay_match)) &&
+ !ACPI_SUCCESS(
+ acpi_is_child_device(device, acpi_dock_match))) {
+ result = -ENODEV;
+ goto end;
+ }
+ }
break;
default:
STRUCT_TO_INT(device->status) =
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 485de134707..293a1cbb47c 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
/* Reprogram control registers and execute _BFS */
acpi_leave_sleep_state_prep(acpi_state);
- /* ACPI 3.0 specs (P62) says that it's the responsabilty
+ /* ACPI 3.0 specs (P62) says that it's the responsibility
* of the OSPM to clear the status bit [ implying that the
* POWER_BUTTON event should not reach userspace ]
*/
@@ -472,11 +472,20 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
if (acpi_target_sleep_state == ACPI_STATE_S0 ||
(wake && adev->wakeup.state.enabled &&
adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
+ acpi_status status;
+
acpi_method[3] = 'W';
- acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
- /* Sanity check */
- if (d_max < d_min)
+ status = acpi_evaluate_integer(handle, acpi_method, NULL,
+ &d_max);
+ if (ACPI_FAILURE(status)) {
+ d_max = d_min;
+ } else if (d_max < d_min) {
+ /* Warn the user of the broken DSDT */
+ printk(KERN_WARNING "ACPI: Wrong value from %s\n",
+ acpi_method);
+ /* Sanitize it */
d_min = d_max;
+ }
}
if (d_min_p)
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 1538355c266..f8df5217d47 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -178,6 +178,9 @@ static int get_date_field(char **p, u32 * value)
* Try to find delimeter, only to insert null. The end of the
* string won't have one, but is still valid.
*/
+ if (*p == NULL)
+ return result;
+
next = strpbrk(*p, "- :");
if (next)
*next++ = '\0';
@@ -190,6 +193,8 @@ static int get_date_field(char **p, u32 * value)
if (next)
*p = next;
+ else
+ *p = NULL;
return result;
}
@@ -251,27 +256,6 @@ acpi_system_write_alarm(struct file *file,
if ((result = get_date_field(&p, &sec)))
goto end;
- if (sec > 59) {
- min += 1;
- sec -= 60;
- }
- if (min > 59) {
- hr += 1;
- min -= 60;
- }
- if (hr > 23) {
- day += 1;
- hr -= 24;
- }
- if (day > 31) {
- mo += 1;
- day -= 31;
- }
- if (mo > 12) {
- yr += 1;
- mo -= 12;
- }
-
spin_lock_irq(&rtc_lock);
rtc_control = CMOS_READ(RTC_CONTROL);
@@ -288,24 +272,24 @@ acpi_system_write_alarm(struct file *file,
spin_unlock_irq(&rtc_lock);
if (sec > 59) {
- min++;
- sec -= 60;
+ min += sec/60;
+ sec = sec%60;
}
if (min > 59) {
- hr++;
- min -= 60;
+ hr += min/60;
+ min = min%60;
}
if (hr > 23) {
- day++;
- hr -= 24;
+ day += hr/24;
+ hr = hr%24;
}
if (day > 31) {
- mo++;
- day -= 31;
+ mo += day/32;
+ day = day%32;
}
if (mo > 12) {
- yr++;
- mo -= 12;
+ yr += mo/13;
+ mo = mo%13;
}
spin_lock_irq(&rtc_lock);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 5ffe0ea1896..ce881713f7a 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -40,6 +40,8 @@ ACPI_MODULE_NAME("system");
#define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DEVICE_NAME "System"
+u32 acpi_irq_handled;
+
/*
* Make ACPICA version work as module param
*/
@@ -166,6 +168,212 @@ static int acpi_system_sysfs_init(void)
return 0;
}
+/*
+ * Detailed ACPI IRQ counters in /sys/firmware/acpi/interrupts/
+ * See Documentation/ABI/testing/sysfs-firmware-acpi
+ */
+
+#define COUNT_GPE 0
+#define COUNT_SCI 1 /* acpi_irq_handled */
+#define COUNT_ERROR 2 /* other */
+#define NUM_COUNTERS_EXTRA 3
+
+static u32 *all_counters;
+static u32 num_gpes;
+static u32 num_counters;
+static struct attribute **all_attrs;
+static u32 acpi_gpe_count;
+
+static struct attribute_group interrupt_stats_attr_group = {
+ .name = "interrupts",
+};
+static struct kobj_attribute *counter_attrs;
+
+static int count_num_gpes(void)
+{
+ int count = 0;
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+ struct acpi_gpe_block_info *gpe_block;
+ acpi_cpu_flags flags;
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+ while (gpe_xrupt_info) {
+ gpe_block = gpe_xrupt_info->gpe_block_list_head;
+ while (gpe_block) {
+ count += gpe_block->register_count *
+ ACPI_GPE_REGISTER_WIDTH;
+ gpe_block = gpe_block->next;
+ }
+ gpe_xrupt_info = gpe_xrupt_info->next;
+ }
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+ return count;
+}
+
+static void delete_gpe_attr_array(void)
+{
+ u32 *tmp = all_counters;
+
+ all_counters = NULL;
+ kfree(tmp);
+
+ if (counter_attrs) {
+ int i;
+
+ for (i = 0; i < num_gpes; i++)
+ kfree(counter_attrs[i].attr.name);
+
+ kfree(counter_attrs);
+ }
+ kfree(all_attrs);
+
+ return;
+}
+
+void acpi_os_gpe_count(u32 gpe_number)
+{
+ acpi_gpe_count++;
+
+ if (!all_counters)
+ return;
+
+ if (gpe_number < num_gpes)
+ all_counters[gpe_number]++;
+ else
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+
+ return;
+}
+
+void acpi_os_fixed_event_count(u32 event_number)
+{
+ if (!all_counters)
+ return;
+
+ if (event_number < ACPI_NUM_FIXED_EVENTS)
+ all_counters[num_gpes + event_number]++;
+ else
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+
+ return;
+}
+
+static ssize_t counter_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
+ acpi_irq_handled;
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
+ acpi_gpe_count;
+
+ return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
+}
+
+/*
+ * counter_set() sets the specified counter.
+ * setting the total "sci" file to any value clears all counters.
+ */
+static ssize_t counter_set(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t size)
+{
+ int index = attr - counter_attrs;
+
+ if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
+ int i;
+ for (i = 0; i < num_counters; ++i)
+ all_counters[i] = 0;
+ acpi_gpe_count = 0;
+ acpi_irq_handled = 0;
+
+ } else
+ all_counters[index] = strtoul(buf, NULL, 0);
+
+ return size;
+}
+
+void acpi_irq_stats_init(void)
+{
+ int i;
+
+ if (all_counters)
+ return;
+
+ num_gpes = count_num_gpes();
+ num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
+
+ all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1),
+ GFP_KERNEL);
+ if (all_attrs == NULL)
+ return;
+
+ all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
+ if (all_counters == NULL)
+ goto fail;
+
+ counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
+ GFP_KERNEL);
+ if (counter_attrs == NULL)
+ goto fail;
+
+ for (i = 0; i < num_counters; ++i) {
+ char buffer[10];
+ char *name;
+
+ if (i < num_gpes)
+ sprintf(buffer, "gpe%02X", i);
+ else if (i == num_gpes + ACPI_EVENT_PMTIMER)
+ sprintf(buffer, "ff_pmtimer");
+ else if (i == num_gpes + ACPI_EVENT_GLOBAL)
+ sprintf(buffer, "ff_gbl_lock");
+ else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
+ sprintf(buffer, "ff_pwr_btn");
+ else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
+ sprintf(buffer, "ff_slp_btn");
+ else if (i == num_gpes + ACPI_EVENT_RTC)
+ sprintf(buffer, "ff_rt_clk");
+ else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
+ sprintf(buffer, "gpe_all");
+ else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
+ sprintf(buffer, "sci");
+ else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
+ sprintf(buffer, "error");
+ else
+ sprintf(buffer, "bug%02X", i);
+
+ name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
+ if (name == NULL)
+ goto fail;
+ strncpy(name, buffer, strlen(buffer) + 1);
+
+ counter_attrs[i].attr.name = name;
+ counter_attrs[i].attr.mode = 0644;
+ counter_attrs[i].show = counter_show;
+ counter_attrs[i].store = counter_set;
+
+ all_attrs[i] = &counter_attrs[i].attr;
+ }
+
+ interrupt_stats_attr_group.attrs = all_attrs;
+ sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group);
+ return;
+
+fail:
+ delete_gpe_attr_array();
+ return;
+}
+
+static void __exit interrupt_stats_exit(void)
+{
+ sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
+
+ delete_gpe_attr_array();
+
+ return;
+}
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index 0a7d7afac25..7385efa6162 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,6 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories
#
-obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index cf8fa514189..9ecb4b6c1e7 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -100,7 +100,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_find_rsdp
+ * FUNCTION: acpi_find_root_pointer
*
* PARAMETERS: table_address - Where the table pointer is returned
*
@@ -219,8 +219,6 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
return_ACPI_STATUS(AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
-
/*******************************************************************************
*
* FUNCTION: acpi_tb_scan_memory_for_rsdp
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5f79b445121..8d4b79b4f93 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -43,7 +43,7 @@
#include <linux/seq_file.h>
#include <linux/reboot.h>
#include <asm/uaccess.h>
-
+#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -65,9 +65,6 @@
#define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
-#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
-#define CELSIUS_TO_KELVIN(t) ((t+273)*10)
-
#define _COMPONENT ACPI_THERMAL_COMPONENT
ACPI_MODULE_NAME("thermal");
@@ -195,6 +192,8 @@ struct acpi_thermal {
struct acpi_thermal_trips trips;
struct acpi_handle_list devices;
struct timer_list timer;
+ struct thermal_zone_device *thermal_zone;
+ int tz_enabled;
struct mutex lock;
};
@@ -321,178 +320,226 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
return 0;
}
-static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
-{
- acpi_status status = AE_OK;
- int i = 0;
+#define ACPI_TRIPS_CRITICAL 0x01
+#define ACPI_TRIPS_HOT 0x02
+#define ACPI_TRIPS_PASSIVE 0x04
+#define ACPI_TRIPS_ACTIVE 0x08
+#define ACPI_TRIPS_DEVICES 0x10
+#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
+#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
- if (!tz)
- return -EINVAL;
+#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
+ ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
+ ACPI_TRIPS_DEVICES)
- /* Critical Shutdown (required) */
-
- status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
- &tz->trips.critical.temperature);
- if (ACPI_FAILURE(status)) {
- tz->trips.critical.flags.valid = 0;
- ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
- return -ENODEV;
- } else {
- tz->trips.critical.flags.valid = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found critical threshold [%lu]\n",
- tz->trips.critical.temperature));
- }
+/*
+ * This exception is thrown out in two cases:
+ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
+ * when re-evaluating the AML code.
+ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
+ * We need to re-bind the cooling devices of a thermal zone when this occurs.
+ */
+#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
+do { \
+ if (flags != ACPI_TRIPS_INIT) \
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
+ "ACPI thermal trip point %s changed\n" \
+ "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
+} while (0)
+
+static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
+{
+ acpi_status status = AE_OK;
+ struct acpi_handle_list devices;
+ int valid = 0;
+ int i;
- if (tz->trips.critical.flags.valid == 1) {
- if (crt == -1) {
+ /* Critical Shutdown (required) */
+ if (flag & ACPI_TRIPS_CRITICAL) {
+ status = acpi_evaluate_integer(tz->device->handle,
+ "_CRT", NULL, &tz->trips.critical.temperature);
+ if (ACPI_FAILURE(status)) {
tz->trips.critical.flags.valid = 0;
- } else if (crt > 0) {
- unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
-
- /*
- * Allow override to lower critical threshold
- */
- if (crt_k < tz->trips.critical.temperature)
- tz->trips.critical.temperature = crt_k;
+ ACPI_EXCEPTION((AE_INFO, status,
+ "No critical threshold"));
+ return -ENODEV;
+ } else {
+ tz->trips.critical.flags.valid = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Found critical threshold [%lu]\n",
+ tz->trips.critical.temperature));
+ }
+ if (tz->trips.critical.flags.valid == 1) {
+ if (crt == -1) {
+ tz->trips.critical.flags.valid = 0;
+ } else if (crt > 0) {
+ unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+ /*
+ * Allow override to lower critical threshold
+ */
+ if (crt_k < tz->trips.critical.temperature)
+ tz->trips.critical.temperature = crt_k;
+ }
}
}
/* Critical Sleep (optional) */
-
- status =
- acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
- &tz->trips.hot.temperature);
- if (ACPI_FAILURE(status)) {
- tz->trips.hot.flags.valid = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
- } else {
- tz->trips.hot.flags.valid = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
- tz->trips.hot.temperature));
- }
-
- /* Passive: Processors (optional) */
-
- if (psv == -1) {
- status = AE_SUPPORT;
- } else if (psv > 0) {
- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
- status = AE_OK;
- } else {
+ if (flag & ACPI_TRIPS_HOT) {
status = acpi_evaluate_integer(tz->device->handle,
- "_PSV", NULL, &tz->trips.passive.temperature);
+ "_HOT", NULL, &tz->trips.hot.temperature);
+ if (ACPI_FAILURE(status)) {
+ tz->trips.hot.flags.valid = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No hot threshold\n"));
+ } else {
+ tz->trips.hot.flags.valid = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Found hot threshold [%lu]\n",
+ tz->trips.critical.temperature));
+ }
}
- if (ACPI_FAILURE(status)) {
- tz->trips.passive.flags.valid = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
- } else {
- tz->trips.passive.flags.valid = 1;
-
- status =
- acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,
- &tz->trips.passive.tc1);
- if (ACPI_FAILURE(status))
- tz->trips.passive.flags.valid = 0;
-
- status =
- acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
- &tz->trips.passive.tc2);
- if (ACPI_FAILURE(status))
- tz->trips.passive.flags.valid = 0;
+ /* Passive (optional) */
+ if (flag & ACPI_TRIPS_PASSIVE) {
+ valid = tz->trips.passive.flags.valid;
+ if (psv == -1) {
+ status = AE_SUPPORT;
+ } else if (psv > 0) {
+ tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+ status = AE_OK;
+ } else {
+ status = acpi_evaluate_integer(tz->device->handle,
+ "_PSV", NULL, &tz->trips.passive.temperature);
+ }
- status =
- acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
- &tz->trips.passive.tsp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
-
- status =
- acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
- &tz->trips.passive.devices);
+ else {
+ tz->trips.passive.flags.valid = 1;
+ if (flag == ACPI_TRIPS_INIT) {
+ status = acpi_evaluate_integer(
+ tz->device->handle, "_TC1",
+ NULL, &tz->trips.passive.tc1);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+ status = acpi_evaluate_integer(
+ tz->device->handle, "_TC2",
+ NULL, &tz->trips.passive.tc2);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+ status = acpi_evaluate_integer(
+ tz->device->handle, "_TSP",
+ NULL, &tz->trips.passive.tsp);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+ }
+ }
+ }
+ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
+ memset(&devices, 0, sizeof(struct acpi_handle_list));
+ status = acpi_evaluate_reference(tz->device->handle, "_PSL",
+ NULL, &devices);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
-
- if (!tz->trips.passive.flags.valid)
- printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
else
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found passive threshold [%lu]\n",
- tz->trips.passive.temperature));
- }
+ tz->trips.passive.flags.valid = 1;
- /* Active: Fans, etc. (optional) */
+ if (memcmp(&tz->trips.passive.devices, &devices,
+ sizeof(struct acpi_handle_list))) {
+ memcpy(&tz->trips.passive.devices, &devices,
+ sizeof(struct acpi_handle_list));
+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+ }
+ }
+ if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
+ if (valid != tz->trips.passive.flags.valid)
+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
+ }
+ /* Active (optional) */
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
+ valid = tz->trips.active[i].flags.valid;
if (act == -1)
- break; /* disable all active trip points */
-
- status = acpi_evaluate_integer(tz->device->handle,
- name, NULL, &tz->trips.active[i].temperature);
-
- if (ACPI_FAILURE(status)) {
- if (i == 0) /* no active trip points */
+ break; /* disable all active trip points */
+
+ if (flag & ACPI_TRIPS_ACTIVE) {
+ status = acpi_evaluate_integer(tz->device->handle,
+ name, NULL, &tz->trips.active[i].temperature);
+ if (ACPI_FAILURE(status)) {
+ tz->trips.active[i].flags.valid = 0;
+ if (i == 0)
+ break;
+ if (act <= 0)
+ break;
+ if (i == 1)
+ tz->trips.active[0].temperature =
+ CELSIUS_TO_KELVIN(act);
+ else
+ /*
+ * Don't allow override higher than
+ * the next higher trip point
+ */
+ tz->trips.active[i - 1].temperature =
+ (tz->trips.active[i - 2].temperature <
+ CELSIUS_TO_KELVIN(act) ?
+ tz->trips.active[i - 2].temperature :
+ CELSIUS_TO_KELVIN(act));
break;
- if (act <= 0) /* no override requested */
- break;
- if (i == 1) { /* 1 trip point */
- tz->trips.active[0].temperature =
- CELSIUS_TO_KELVIN(act);
- } else { /* multiple trips */
- /*
- * Don't allow override higher than
- * the next higher trip point
- */
- tz->trips.active[i - 1].temperature =
- (tz->trips.active[i - 2].temperature <
- CELSIUS_TO_KELVIN(act) ?
- tz->trips.active[i - 2].temperature :
- CELSIUS_TO_KELVIN(act));
- }
- break;
+ } else
+ tz->trips.active[i].flags.valid = 1;
}
name[2] = 'L';
- status =
- acpi_evaluate_reference(tz->device->handle, name, NULL,
- &tz->trips.active[i].devices);
- if (ACPI_SUCCESS(status)) {
- tz->trips.active[i].flags.valid = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found active threshold [%d]:[%lu]\n",
- i, tz->trips.active[i].temperature));
- } else
- ACPI_EXCEPTION((AE_INFO, status,
- "Invalid active threshold [%d]", i));
+ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
+ memset(&devices, 0, sizeof(struct acpi_handle_list));
+ status = acpi_evaluate_reference(tz->device->handle,
+ name, NULL, &devices);
+ if (ACPI_FAILURE(status))
+ tz->trips.active[i].flags.valid = 0;
+ else
+ tz->trips.active[i].flags.valid = 1;
+
+ if (memcmp(&tz->trips.active[i].devices, &devices,
+ sizeof(struct acpi_handle_list))) {
+ memcpy(&tz->trips.active[i].devices, &devices,
+ sizeof(struct acpi_handle_list));
+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+ }
+ }
+ if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
+ if (valid != tz->trips.active[i].flags.valid)
+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
+
+ if (!tz->trips.active[i].flags.valid)
+ break;
+ }
+
+ if (flag & ACPI_TRIPS_DEVICES) {
+ memset(&devices, 0, sizeof(struct acpi_handle_list));
+ status = acpi_evaluate_reference(tz->device->handle, "_TZD",
+ NULL, &devices);
+ if (memcmp(&tz->devices, &devices,
+ sizeof(struct acpi_handle_list))) {
+ memcpy(&tz->devices, &devices,
+ sizeof(struct acpi_handle_list));
+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+ }
}
return 0;
}
-static int acpi_thermal_get_devices(struct acpi_thermal *tz)
+static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
{
- acpi_status status = AE_OK;
-
-
- if (!tz)
- return -EINVAL;
-
- status =
- acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- return 0;
+ return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
}
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
- if (!tz || !tz->trips.critical.flags.valid || nocrt)
+ if (!tz || !tz->trips.critical.flags.valid)
return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) {
@@ -501,9 +548,6 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
} else if (tz->trips.critical.flags.enabled)
tz->trips.critical.flags.enabled = 0;
- printk(KERN_EMERG
- "Critical temperature reached (%ld C), shutting down.\n",
- KELVIN_TO_CELSIUS(tz->temperature));
acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
@@ -511,14 +555,20 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
- orderly_poweroff(true);
+ /* take no action if nocrt is set */
+ if(!nocrt) {
+ printk(KERN_EMERG
+ "Critical temperature reached (%ld C), shutting down.\n",
+ KELVIN_TO_CELSIUS(tz->temperature));
+ orderly_poweroff(true);
+ }
return 0;
}
static int acpi_thermal_hot(struct acpi_thermal *tz)
{
- if (!tz || !tz->trips.hot.flags.valid || nocrt)
+ if (!tz || !tz->trips.hot.flags.valid)
return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) {
@@ -534,7 +584,7 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
ACPI_THERMAL_NOTIFY_HOT,
tz->trips.hot.flags.enabled);
- /* TBD: Call user-mode "sleep(S4)" function */
+ /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
return 0;
}
@@ -732,6 +782,9 @@ static void acpi_thermal_check(void *data)
if (result)
goto unlock;
+ if (!tz->tz_enabled)
+ goto unlock;
+
memset(&tz->state, 0, sizeof(tz->state));
/*
@@ -825,6 +878,290 @@ static void acpi_thermal_check(void *data)
mutex_unlock(&tz->lock);
}
+/* sys I/F for generic thermal sysfs support */
+static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
+{
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (!tz)
+ return -EINVAL;
+
+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
+}
+
+static const char enabled[] = "kernel";
+static const char disabled[] = "user";
+static int thermal_get_mode(struct thermal_zone_device *thermal,
+ char *buf)
+{
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (!tz)
+ return -EINVAL;
+
+ return sprintf(buf, "%s\n", tz->tz_enabled ?
+ enabled : disabled);
+}
+
+static int thermal_set_mode(struct thermal_zone_device *thermal,
+ const char *buf)
+{
+ struct acpi_thermal *tz = thermal->devdata;
+ int enable;
+
+ if (!tz)
+ return -EINVAL;
+
+ /*
+ * enable/disable thermal management from ACPI thermal driver
+ */
+ if (!strncmp(buf, enabled, sizeof enabled - 1))
+ enable = 1;
+ else if (!strncmp(buf, disabled, sizeof disabled - 1))
+ enable = 0;
+ else
+ return -EINVAL;
+
+ if (enable != tz->tz_enabled) {
+ tz->tz_enabled = enable;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "%s ACPI thermal control\n",
+ tz->tz_enabled ? enabled : disabled));
+ acpi_thermal_check(tz);
+ }
+ return 0;
+}
+
+static int thermal_get_trip_type(struct thermal_zone_device *thermal,
+ int trip, char *buf)
+{
+ struct acpi_thermal *tz = thermal->devdata;
+ int i;
+
+ if (!tz || trip < 0)
+ return -EINVAL;
+
+ if (tz->trips.critical.flags.valid) {
+ if (!trip)
+ return sprintf(buf, "critical\n");
+ trip--;
+ }
+
+ if (tz->trips.hot.flags.valid) {
+ if (!trip)
+ return sprintf(buf, "hot\n");
+ trip--;
+ }
+
+ if (tz->trips.passive.flags.valid) {
+ if (!trip)
+ return sprintf(buf, "passive\n");
+ trip--;
+ }
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+ tz->trips.active[i].flags.valid; i++) {
+ if (!trip)
+ return sprintf(buf, "active%d\n", i);
+ trip--;
+ }
+
+ return -EINVAL;
+}
+
+static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
+ int trip, char *buf)
+{
+ struct acpi_thermal *tz = thermal->devdata;
+ int i;
+
+ if (!tz || trip < 0)
+ return -EINVAL;
+
+ if (tz->trips.critical.flags.valid) {
+ if (!trip)
+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+ tz->trips.critical.temperature));
+ trip--;
+ }
+
+ if (tz->trips.hot.flags.valid) {
+ if (!trip)
+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+ tz->trips.hot.temperature));
+ trip--;
+ }
+
+ if (tz->trips.passive.flags.valid) {
+ if (!trip)
+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+ tz->trips.passive.temperature));
+ trip--;
+ }
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+ tz->trips.active[i].flags.valid; i++) {
+ if (!trip)
+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+ tz->trips.active[i].temperature));
+ trip--;
+ }
+
+ return -EINVAL;
+}
+
+typedef int (*cb)(struct thermal_zone_device *, int,
+ struct thermal_cooling_device *);
+static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev,
+ cb action)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_thermal *tz = thermal->devdata;
+ struct acpi_device *dev;
+ acpi_status status;
+ acpi_handle handle;
+ int i;
+ int j;
+ int trip = -1;
+ int result = 0;
+
+ if (tz->trips.critical.flags.valid)
+ trip++;
+
+ if (tz->trips.hot.flags.valid)
+ trip++;
+
+ if (tz->trips.passive.flags.valid) {
+ trip++;
+ for (i = 0; i < tz->trips.passive.devices.count;
+ i++) {
+ handle = tz->trips.passive.devices.handles[i];
+ status = acpi_bus_get_device(handle, &dev);
+ if (ACPI_SUCCESS(status) && (dev == device)) {
+ result = action(thermal, trip, cdev);
+ if (result)
+ goto failed;
+ }
+ }
+ }
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ if (!tz->trips.active[i].flags.valid)
+ break;
+ trip++;
+ for (j = 0;
+ j < tz->trips.active[i].devices.count;
+ j++) {
+ handle = tz->trips.active[i].devices.handles[j];
+ status = acpi_bus_get_device(handle, &dev);
+ if (ACPI_SUCCESS(status) && (dev == device)) {
+ result = action(thermal, trip, cdev);
+ if (result)
+ goto failed;
+ }
+ }
+ }
+
+ for (i = 0; i < tz->devices.count; i++) {
+ handle = tz->devices.handles[i];
+ status = acpi_bus_get_device(handle, &dev);
+ if (ACPI_SUCCESS(status) && (dev == device)) {
+ result = action(thermal, -1, cdev);
+ if (result)
+ goto failed;
+ }
+ }
+
+failed:
+ return result;
+}
+
+static int
+acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ return acpi_thermal_cooling_device_cb(thermal, cdev,
+ thermal_zone_bind_cooling_device);
+}
+
+static int
+acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ return acpi_thermal_cooling_device_cb(thermal, cdev,
+ thermal_zone_unbind_cooling_device);
+}
+
+static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
+ .bind = acpi_thermal_bind_cooling_device,
+ .unbind = acpi_thermal_unbind_cooling_device,
+ .get_temp = thermal_get_temp,
+ .get_mode = thermal_get_mode,
+ .set_mode = thermal_set_mode,
+ .get_trip_type = thermal_get_trip_type,
+ .get_trip_temp = thermal_get_trip_temp,
+};
+
+static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
+{
+ int trips = 0;
+ int result;
+ acpi_status status;
+ int i;
+
+ if (tz->trips.critical.flags.valid)
+ trips++;
+
+ if (tz->trips.hot.flags.valid)
+ trips++;
+
+ if (tz->trips.passive.flags.valid)
+ trips++;
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+ tz->trips.active[i].flags.valid; i++, trips++);
+ tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+ trips, tz, &acpi_thermal_zone_ops);
+ if (!tz->thermal_zone)
+ return -ENODEV;
+
+ result = sysfs_create_link(&tz->device->dev.kobj,
+ &tz->thermal_zone->device.kobj, "thermal_zone");
+ if (result)
+ return result;
+
+ result = sysfs_create_link(&tz->thermal_zone->device.kobj,
+ &tz->device->dev.kobj, "device");
+ if (result)
+ return result;
+
+ status = acpi_attach_data(tz->device->handle,
+ acpi_bus_private_data_handler,
+ tz->thermal_zone);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error attaching device data\n"));
+ return -ENODEV;
+ }
+
+ tz->tz_enabled = 1;
+
+ printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
+ tz->device->dev.bus_id, tz->thermal_zone->id);
+ return 0;
+}
+
+static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
+{
+ sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
+ sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
+ thermal_zone_device_unregister(tz->thermal_zone);
+ tz->thermal_zone = NULL;
+ acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
+}
+
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -1181,15 +1518,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
acpi_thermal_check(tz);
break;
case ACPI_THERMAL_NOTIFY_THRESHOLDS:
- acpi_thermal_get_trip_points(tz);
+ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
acpi_thermal_check(tz);
acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
device->dev.bus_id, event, 0);
break;
case ACPI_THERMAL_NOTIFY_DEVICES:
- if (tz->flags.devices)
- acpi_thermal_get_devices(tz);
+ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
+ acpi_thermal_check(tz);
acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
device->dev.bus_id, event, 0);
@@ -1232,11 +1569,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
else
acpi_thermal_get_polling_frequency(tz);
- /* Get devices in this thermal zone [_TZD] (optional) */
- result = acpi_thermal_get_devices(tz);
- if (!result)
- tz->flags.devices = 1;
-
return 0;
}
@@ -1260,13 +1592,19 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz;
mutex_init(&tz->lock);
+
+
result = acpi_thermal_get_info(tz);
if (result)
- goto end;
+ goto free_memory;
+
+ result = acpi_thermal_register_thermal_zone(tz);
+ if (result)
+ goto free_memory;
result = acpi_thermal_add_fs(device);
if (result)
- goto end;
+ goto unregister_thermal_zone;
init_timer(&tz->timer);
@@ -1277,19 +1615,21 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_thermal_notify, tz);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
- goto end;
+ goto remove_fs;
}
printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
acpi_device_name(device), acpi_device_bid(device),
KELVIN_TO_CELSIUS(tz->temperature));
+ goto end;
- end:
- if (result) {
- acpi_thermal_remove_fs(device);
- kfree(tz);
- }
-
+remove_fs:
+ acpi_thermal_remove_fs(device);
+unregister_thermal_zone:
+ thermal_zone_device_unregister(tz->thermal_zone);
+free_memory:
+ kfree(tz);
+end:
return result;
}
@@ -1329,6 +1669,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
}
acpi_thermal_remove_fs(device);
+ acpi_thermal_unregister_thermal_zone(tz);
mutex_destroy(&tz->lock);
kfree(tz);
return 0;
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 93ea8290b4f..630c9a2c5b7 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -671,7 +671,6 @@ void acpi_ut_init_globals(void)
/* GPE support */
- acpi_gpe_count = 0;
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -735,4 +734,3 @@ void acpi_ut_init_globals(void)
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
- ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index bd77e81e81c..82815cff15a 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -34,6 +34,7 @@
#include <linux/seq_file.h>
#include <linux/input.h>
#include <linux/backlight.h>
+#include <linux/thermal.h>
#include <linux/video_output.h>
#include <asm/uaccess.h>
@@ -179,6 +180,7 @@ struct acpi_video_device {
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight;
+ struct thermal_cooling_device *cdev;
struct output_device *output_dev;
};
@@ -292,18 +294,26 @@ static int acpi_video_device_set_state(struct acpi_video_device *device, int sta
static int acpi_video_get_brightness(struct backlight_device *bd)
{
unsigned long cur_level;
+ int i;
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_get_level_current(vd, &cur_level);
- return (int) cur_level;
+ for (i = 2; i < vd->brightness->count; i++) {
+ if (vd->brightness->levels[i] == cur_level)
+ /* The first two entries are special - see page 575
+ of the ACPI spec 3.0 */
+ return i-2;
+ }
+ return 0;
}
static int acpi_video_set_brightness(struct backlight_device *bd)
{
- int request_level = bd->props.brightness;
+ int request_level = bd->props.brightness+2;
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
- acpi_video_device_lcd_set_level(vd, request_level);
+ acpi_video_device_lcd_set_level(vd,
+ vd->brightness->levels[request_level]);
return 0;
}
@@ -334,6 +344,54 @@ static struct output_properties acpi_output_properties = {
.set_state = acpi_video_output_set,
.get_status = acpi_video_output_get,
};
+
+
+/* thermal cooling device callbacks */
+static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_video_device *video = acpi_driver_data(device);
+
+ return sprintf(buf, "%d\n", video->brightness->count - 3);
+}
+
+static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_video_device *video = acpi_driver_data(device);
+ unsigned long level;
+ int state;
+
+ acpi_video_device_lcd_get_level_current(video, &level);
+ for (state = 2; state < video->brightness->count; state++)
+ if (level == video->brightness->levels[state])
+ return sprintf(buf, "%d\n",
+ video->brightness->count - state - 1);
+
+ return -EINVAL;
+}
+
+static int
+video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+ struct acpi_device *device = cdev->devdata;
+ struct acpi_video_device *video = acpi_driver_data(device);
+ int level;
+
+ if ( state >= video->brightness->count - 2)
+ return -EINVAL;
+
+ state = video->brightness->count - state;
+ level = video->brightness->levels[state -1];
+ return acpi_video_device_lcd_set_level(video, level);
+}
+
+static struct thermal_cooling_device_ops video_cooling_ops = {
+ .get_max_state = video_get_max_state,
+ .get_cur_state = video_get_cur_state,
+ .set_cur_state = video_set_cur_state,
+};
+
/* --------------------------------------------------------------------------
Video Management
-------------------------------------------------------------------------- */
@@ -652,7 +710,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj);
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
- unsigned long tmp;
+ int result;
static int count = 0;
char *name;
name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
@@ -660,14 +718,30 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
return;
sprintf(name, "acpi_video%d", count++);
- acpi_video_device_lcd_get_level_current(device, &tmp);
device->backlight = backlight_device_register(name,
NULL, device, &acpi_backlight_ops);
- device->backlight->props.max_brightness = max_level;
- device->backlight->props.brightness = (int)tmp;
+ device->backlight->props.max_brightness = device->brightness->count-3;
+ device->backlight->props.brightness = acpi_video_get_brightness(device->backlight);
backlight_update_status(device->backlight);
-
kfree(name);
+
+ device->cdev = thermal_cooling_device_register("LCD",
+ device->dev, &video_cooling_ops);
+ if (device->cdev) {
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev->dev.bus_id, device->cdev->id);
+ result = sysfs_create_link(&device->dev->dev.kobj,
+ &device->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&device->cdev->device.kobj,
+ &device->dev->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ }
}
if (device->cap._DCS && device->cap._DSS){
static int count = 0;
@@ -1256,8 +1330,37 @@ acpi_video_bus_write_DOS(struct file *file,
static int acpi_video_bus_add_fs(struct acpi_device *device)
{
+ long device_id;
+ int status;
struct proc_dir_entry *entry = NULL;
struct acpi_video_bus *video;
+ struct device *dev;
+
+ status =
+ acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+
+ if (!ACPI_SUCCESS(status))
+ return -ENODEV;
+
+ /* We need to attempt to determine whether the _ADR refers to a
+ PCI device or not. There's no terribly good way to do this,
+ so the best we can hope for is to assume that there'll never
+ be a video device in the host bridge */
+ if (device_id >= 0x10000) {
+ /* It looks like a PCI device. Does it exist? */
+ dev = acpi_get_physical_device(device->handle);
+ } else {
+ /* It doesn't look like a PCI device. Does its parent
+ exist? */
+ acpi_handle phandle;
+ if (acpi_get_parent(device->handle, &phandle))
+ return -ENODEV;
+ dev = acpi_get_physical_device(phandle);
+ }
+ if (!dev)
+ return -ENODEV;
+ put_device(dev);
+
video = acpi_driver_data(device);
@@ -1729,6 +1832,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
backlight_device_unregister(device->backlight);
+ if (device->cdev) {
+ sysfs_remove_link(&device->dev->dev.kobj,
+ "thermal_cooling");
+ sysfs_remove_link(&device->cdev->device.kobj,
+ "device");
+ thermal_cooling_device_unregister(device->cdev);
+ device->cdev = NULL;
+ }
video_output_unregister(device->output_dev);
return 0;