ACPI: SBS: Run notifier callback with mutex held. From: Alexey Starikovskiy EC may send notifications faster than we are able to serve them. Reference: http://bugzilla.kernel.org/show_bug.cgi?id=13109 Signed-off-by: Alexey Starikovskiy --- drivers/acpi/sbs.c | 3 +++ drivers/acpi/sbshc.c | 10 ++++++++++ 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 4b214b7..82b0343 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -882,6 +882,8 @@ static void acpi_sbs_callback(void *context) struct acpi_battery *bat; u8 saved_charger_state = sbs->charger_present; u8 saved_battery_state; + /* check if some parallel SBS access is going on */ + mutex_lock(&sbs->lock); acpi_ac_get_present(sbs); if (sbs->charger_present != saved_charger_state) { #ifdef CONFIG_ACPI_PROC_EVENT @@ -913,6 +915,7 @@ static void acpi_sbs_callback(void *context) #endif } } + mutex_unlock(&sbs->lock); } static int acpi_sbs_remove(struct acpi_device *device, int type); diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 0619734..eba8530 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -212,17 +212,21 @@ int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback); +static int alarm_is_pending; + static inline void acpi_smbus_callback(void *context) { struct acpi_smb_hc *hc = context; if (hc->callback) hc->callback(hc->context); + alarm_is_pending = 0; } static int smbus_alarm(void *context) { struct acpi_smb_hc *hc = context; union acpi_smb_status status; + static unsigned long alarm_time = 0; u8 address; if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw)) return 0; @@ -232,6 +236,9 @@ static int smbus_alarm(void *context) if (!status.fields.alarm) return 0; mutex_lock(&hc->lock); + if (alarm_is_pending || + time_before(jiffies, alarm_time + msecs_to_jiffies(1000))) + goto unlock; smb_hc_read(hc, ACPI_SMB_ALARM_ADDRESS, &address); status.fields.alarm = 0; smb_hc_write(hc, ACPI_SMB_STATUS, status.raw); @@ -240,10 +247,13 @@ static int smbus_alarm(void *context) case ACPI_SBS_CHARGER: case ACPI_SBS_MANAGER: case ACPI_SBS_BATTERY: + alarm_is_pending = 1; + alarm_time = jiffies; acpi_os_execute(OSL_GPE_HANDLER, acpi_smbus_callback, hc); default:; } +unlock: mutex_unlock(&hc->lock); return 0; }