summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSang-Hun Lee <sanlee@nvidia.com>2013-10-08 14:14:24 -0700
committerHarshada Kale <hkale@nvidia.com>2013-10-09 01:27:49 -0700
commit810f9b671e1764f101bf6c0bfa4797edf1f707dc (patch)
treedcb3ee42c34b4b4d14c70982fed1799b044daf9d /drivers
parent08e8dc0ee99d04b8bb9266396961e68291f5e2b2 (diff)
input: misc: inv: fix race in shutdown and suspend
Problem description: - Write to shutdown flag is not mutex protected - nvi_work_func may be scheduled after shutdown or suspend - kfifo is being freed for shutdown, which could corrupt memory if there is a further access to kfifo by nvi_pm_exit and its function calls Fix description: - Encapsulate write to shutdown flag with a mutex, to ensure readers get valid information - Wait for nvi_work_func to complete during shutdown and suspend - Free kfifo only during remove Bug 1361923 Change-Id: I64dabfb21a289354e7f7c58ac408dc48bcff9267 Signed-off-by: Sang-Hun Lee <sanlee@nvidia.com> Reviewed-on: http://git-master/r/283813 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Deepak Nibade <dnibade@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/misc/mpu/inv_gyro.c43
1 files changed, 27 insertions, 16 deletions
diff --git a/drivers/input/misc/mpu/inv_gyro.c b/drivers/input/misc/mpu/inv_gyro.c
index eaf86c17c215..d1c2bcd93868 100644
--- a/drivers/input/misc/mpu/inv_gyro.c
+++ b/drivers/input/misc/mpu/inv_gyro.c
@@ -4381,6 +4381,8 @@ static int nvi_suspend(struct device *dev)
spin_unlock_irqrestore(&inf->time_stamp_lock, flags);
synchronize_irq(inf->i2c->irq);
+ flush_work_sync(&inf->work_struct);
+
mutex_lock(&inf->mutex);
inf->suspend = true;
err = nvi_pm(inf, NVI_PM_OFF);
@@ -4423,29 +4425,34 @@ static void nvi_shutdown(struct i2c_client *client)
int i;
unsigned long flags;
inf = i2c_get_clientdata(client);
+ if (inf == NULL)
+ return;
+
spin_lock_irqsave(&inf->time_stamp_lock, flags);
if (!inf->irq_disabled)
disable_irq_nosync(client->irq);
inf->irq_disabled = true;
spin_unlock_irqrestore(&inf->time_stamp_lock, flags);
synchronize_irq(inf->i2c->irq);
- if (inf != NULL) {
- for (i = 0; i < AUX_PORT_SPECIAL; i++) {
- if (inf->aux.port[i].nmp.shutdown_bypass) {
- nvi_aux_bypass_enable(inf, true);
- break;
- }
+
+ flush_work_sync(&inf->work_struct);
+
+ mutex_lock(&inf->mutex);
+ for (i = 0; i < AUX_PORT_SPECIAL; i++) {
+ if (inf->aux.port[i].nmp.shutdown_bypass) {
+ nvi_aux_bypass_enable(inf, true);
+ break;
}
- inf->shutdown = true;
- if (inf->inv_dev)
- remove_sysfs_interfaces(inf);
- kfifo_free(&inf->trigger.timestamps);
- free_irq(client->irq, inf);
- if (inf->idev)
- input_unregister_device(inf->idev);
- if ((INV_ITG3500 != inf->chip_type) && (inf->idev_dmp))
- input_unregister_device(inf->idev_dmp);
}
+ inf->shutdown = true;
+ if (inf->inv_dev)
+ remove_sysfs_interfaces(inf);
+ free_irq(client->irq, inf);
+ mutex_unlock(&inf->mutex);
+ if (inf->idev)
+ input_unregister_device(inf->idev);
+ if ((INV_ITG3500 != inf->chip_type) && (inf->idev_dmp))
+ input_unregister_device(inf->idev_dmp);
}
static int nvi_remove(struct i2c_client *client)
@@ -4456,6 +4463,7 @@ static int nvi_remove(struct i2c_client *client)
inf = i2c_get_clientdata(client);
if (inf != NULL) {
nvi_pm_exit(inf);
+ kfifo_free(&inf->trigger.timestamps);
kfree(inf);
}
dev_info(&client->dev, "%s\n", __func__);
@@ -4471,7 +4479,10 @@ static void nvi_work_func(struct work_struct *work)
mutex_lock(&inf->mutex);
nvi_pm_current = inf->pm;
nvi_pm(inf, NVI_PM_OFF_FORCE);
- if (!(inf->suspend || inf->shutdown)) {
+ /*
+ * If suspending, no need to revive the power state
+ */
+ if (!(inf->suspend)) {
nvi_pm(inf, nvi_pm_current);
nvi_reset(inf, true, true);
nvi_global_delay(inf);