aboutsummaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/battery.c47
-rw-r--r--drivers/acpi/processor_idle.c32
-rw-r--r--drivers/acpi/tables/tbutils.c71
3 files changed, 126 insertions, 24 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index d7b499fe0cd..81651032791 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -113,7 +113,7 @@ struct acpi_battery_info {
acpi_string oem_info;
};
-enum acpi_battery_files {
+enum acpi_battery_files{
ACPI_BATTERY_INFO = 0,
ACPI_BATTERY_STATE,
ACPI_BATTERY_ALARM,
@@ -129,14 +129,13 @@ struct acpi_battery_flags {
};
struct acpi_battery {
+ struct mutex mutex;
struct acpi_device *device;
struct acpi_battery_flags flags;
struct acpi_buffer bif_data;
struct acpi_buffer bst_data;
- struct mutex lock;
unsigned long alarm;
unsigned long update_time[ACPI_BATTERY_NUMFILES];
-
};
inline int acpi_battery_present(struct acpi_battery *battery)
@@ -236,10 +235,10 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
return 0;
/* Evaluate _BIF */
- mutex_lock(&battery->lock);
- status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF",
- NULL, &buffer);
- mutex_unlock(&battery->lock);
+
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
return -ENODEV;
@@ -286,10 +285,10 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
return 0;
/* Evaluate _BST */
- mutex_lock(&battery->lock);
- status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST",
- NULL, &buffer);
- mutex_unlock(&battery->lock);
+
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
return -ENODEV;
@@ -337,10 +336,9 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
arg0.integer.value = alarm;
- mutex_lock(&battery->lock);
- status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
&arg_list, NULL);
- mutex_unlock(&battery->lock);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -660,6 +658,8 @@ acpi_battery_write_alarm(struct file *file,
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
+ mutex_lock(&battery->mutex);
+
result = acpi_battery_update(battery, 1, &update_result);
if (result) {
result = -ENODEV;
@@ -688,7 +688,9 @@ acpi_battery_write_alarm(struct file *file,
acpi_battery_check_result(battery, result);
if (!result)
- return count;
+ result = count;
+
+ mutex_unlock(&battery->mutex);
return result;
}
@@ -712,6 +714,8 @@ static int acpi_battery_read(int fid, struct seq_file *seq)
int update_result = ACPI_BATTERY_NONE_UPDATE;
int update = 0;
+ mutex_lock(&battery->mutex);
+
update = (get_seconds() - battery->update_time[fid] >= update_time);
update = (update | battery->flags.update[fid]);
@@ -729,6 +733,7 @@ static int acpi_battery_read(int fid, struct seq_file *seq)
result = acpi_read_funcs[fid].print(seq, result);
acpi_battery_check_result(battery, result);
battery->flags.update[fid] = result;
+ mutex_unlock(&battery->mutex);
return result;
}
@@ -892,7 +897,10 @@ static int acpi_battery_add(struct acpi_device *device)
if (!battery)
return -ENOMEM;
- mutex_init(&battery->lock);
+ mutex_init(&battery->mutex);
+
+ mutex_lock(&battery->mutex);
+
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
@@ -928,6 +936,7 @@ static int acpi_battery_add(struct acpi_device *device)
kfree(battery);
}
+ mutex_unlock(&battery->mutex);
return result;
}
@@ -942,6 +951,8 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
battery = acpi_driver_data(device);
+ mutex_lock(&battery->mutex);
+
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
@@ -952,7 +963,9 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
kfree(battery->bst_data.pointer);
- mutex_destroy(&battery->lock);
+ mutex_unlock(&battery->mutex);
+
+ mutex_destroy(&battery->mutex);
kfree(battery);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index a8634a0655f..d9b8af763e1 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -63,6 +63,7 @@
ACPI_MODULE_NAME("processor_idle");
#define ACPI_PROCESSOR_FILE_POWER "power"
#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
+#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
static void (*pm_idle_save) (void) __read_mostly;
@@ -462,6 +463,9 @@ static void acpi_processor_idle(void)
* TBD: Can't get time duration while in C1, as resumes
* go to an ISR rather than here. Need to instrument
* base interrupt handler.
+ *
+ * Note: the TSC better not stop in C1, sched_clock() will
+ * skew otherwise.
*/
sleep_ticks = 0xFFFFFFFF;
break;
@@ -469,6 +473,8 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C2:
/* Get start time (ticks) */
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ /* Tell the scheduler that we are going deep-idle: */
+ sched_clock_idle_sleep_event();
/* Invoke C2 */
acpi_state_timer_broadcast(pr, cx, 1);
acpi_cstate_enter(cx);
@@ -479,17 +485,22 @@ static void acpi_processor_idle(void)
/* TSC halts in C2, so notify users */
mark_tsc_unstable("possible TSC halt in C2");
#endif
+ /* Compute time (ticks) that we were actually asleep */
+ sleep_ticks = ticks_elapsed(t1, t2);
+
+ /* Tell the scheduler how much we idled: */
+ sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+
/* Re-enable interrupts */
local_irq_enable();
+ /* Do not account our idle-switching overhead: */
+ sleep_ticks -= cx->latency_ticks + C2_OVERHEAD;
+
current_thread_info()->status |= TS_POLLING;
- /* Compute time (ticks) that we were actually asleep */
- sleep_ticks =
- ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
acpi_state_timer_broadcast(pr, cx, 0);
break;
case ACPI_STATE_C3:
-
/*
* disable bus master
* bm_check implies we need ARB_DIS
@@ -518,6 +529,8 @@ static void acpi_processor_idle(void)
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C3 */
acpi_state_timer_broadcast(pr, cx, 1);
+ /* Tell the scheduler that we are going deep-idle: */
+ sched_clock_idle_sleep_event();
acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
@@ -531,12 +544,17 @@ static void acpi_processor_idle(void)
/* TSC halts in C3, so notify users */
mark_tsc_unstable("TSC halts in C3");
#endif
+ /* Compute time (ticks) that we were actually asleep */
+ sleep_ticks = ticks_elapsed(t1, t2);
+ /* Tell the scheduler how much we idled: */
+ sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+
/* Re-enable interrupts */
local_irq_enable();
+ /* Do not account our idle-switching overhead: */
+ sleep_ticks -= cx->latency_ticks + C3_OVERHEAD;
+
current_thread_info()->status |= TS_POLLING;
- /* Compute time (ticks) that we were actually asleep */
- sleep_ticks =
- ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
acpi_state_timer_broadcast(pr, cx, 0);
break;
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 1da64b4518c..8cc9492ffbf 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -51,6 +51,65 @@ ACPI_MODULE_NAME("tbutils")
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,
acpi_native_uint table_entry_size);
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_check_xsdt
+ *
+ * PARAMETERS: address - Pointer to the XSDT
+ *
+ * RETURN: status
+ * AE_OK - XSDT is okay
+ * AE_NO_MEMORY - can't map XSDT
+ * AE_INVALID_TABLE_LENGTH - invalid table length
+ * AE_NULL_ENTRY - XSDT has NULL entry
+ *
+ * DESCRIPTION: validate XSDT
+******************************************************************************/
+
+static acpi_status
+acpi_tb_check_xsdt(acpi_physical_address address)
+{
+ struct acpi_table_header *table;
+ u32 length;
+ u64 xsdt_entry_address;
+ u8 *table_entry;
+ u32 table_count;
+ int i;
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table)
+ return AE_NO_MEMORY;
+
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+ if (length < sizeof(struct acpi_table_header))
+ return AE_INVALID_TABLE_LENGTH;
+
+ table = acpi_os_map_memory(address, length);
+ if (!table)
+ return AE_NO_MEMORY;
+
+ /* Calculate the number of tables described in XSDT */
+ table_count =
+ (u32) ((table->length -
+ sizeof(struct acpi_table_header)) / sizeof(u64));
+ table_entry =
+ ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+ for (i = 0; i < table_count; i++) {
+ ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
+ if (!xsdt_entry_address) {
+ /* XSDT has NULL entry */
+ break;
+ }
+ table_entry += sizeof(u64);
+ }
+ acpi_os_unmap_memory(table, length);
+
+ if (i < table_count)
+ return AE_NULL_ENTRY;
+ else
+ return AE_OK;
+}
/*******************************************************************************
*
@@ -341,6 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
+ acpi_physical_address rsdt_address;
u32 length;
u8 *table_entry;
acpi_status status;
@@ -369,6 +429,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
*/
address = (acpi_physical_address) rsdp->xsdt_physical_address;
table_entry_size = sizeof(u64);
+ rsdt_address = (acpi_physical_address)
+ rsdp->rsdt_physical_address;
} else {
/* Root table is an RSDT (32-bit physical addresses) */
@@ -382,6 +444,15 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
*/
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+ if (table_entry_size == sizeof(u64)) {
+ if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) {
+ /* XSDT has NULL entry, RSDT is used */
+ address = rsdt_address;
+ table_entry_size = sizeof(u32);
+ ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry,"
+ "using RSDT"));
+ }
+ }
/* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));