summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@linaro.org>2011-05-11 10:02:36 +0200
committerHenrik Aberg <henrik.aberg@stericsson.com>2011-05-18 09:40:11 +0200
commite1f3f32118eae27ae9d9d2208d2d02c120f60eab (patch)
treeb64de747f7f128bed35e234e86ac50ff636bf199
parentf6e876d769b5b28f8eac2fa91de4b454b7ab26d3 (diff)
cg2900: Fix crash when transport is closed
This patch fixes crashes caused by transport being removed while users of the CG2900 driver still exist. ST-Ericsson Linux next: Not tested, ER 336652 ST-Ericsson ID: 336652 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I6318ce1086097a4fa63a1793b6795b01ea939715 Signed-off-by: Par-Gunnar Hjalmdahl <par-gunnar.p.hjalmdahl@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21781 Reviewed-by: QATEST Reviewed-by: Lukasz RYMANOWSKI <lukasz.rymanowski@stericsson.com> Conflicts: drivers/bluetooth/btcg2900.c drivers/bluetooth/cg2900_uart.c drivers/mfd/cg2900/cg2900_audio.c drivers/mfd/cg2900/cg2900_char_devices.c
-rw-r--r--drivers/regulator/core.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index cc1d1214766..41b6aa640e1 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -88,7 +88,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static void _notifier_call_chain(struct regulator_dev *rdev,
- unsigned long event, void *data);
+ unsigned long event, void *data, int lock_sublevel);
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
@@ -1439,7 +1439,7 @@ static int _regulator_disable(struct regulator_dev *rdev,
trace_regulator_disable_complete(rdev_get_name(rdev));
_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
- NULL);
+ NULL, 0);
}
/* decrease our supplies ref count and disable if required */
@@ -1512,7 +1512,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
}
/* notify other consumers that power has been forced off */
_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
- REGULATOR_EVENT_DISABLE, NULL);
+ REGULATOR_EVENT_DISABLE, NULL, 0);
}
/* decrease our supplies ref count and disable if required */
@@ -1734,7 +1734,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
if (ret == 0)
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
- NULL);
+ NULL, 0);
trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
@@ -2202,19 +2202,23 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
/* notify regulator consumers and downstream regulator consumers.
* Note mutex must be held by caller.
+ * lock_sublevel should always be 0, only used for recursive calls.
*/
static void _notifier_call_chain(struct regulator_dev *rdev,
- unsigned long event, void *data)
+ unsigned long event, void *data, int lock_sublevel)
{
struct regulator_dev *_rdev;
/* call rdev chain first */
blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+ /* increase sublevel before stepping into nested regulators */
+ lock_sublevel++;
+
/* now notify regulator we supply */
list_for_each_entry(_rdev, &rdev->supply_list, slist) {
- mutex_lock(&_rdev->mutex);
- _notifier_call_chain(_rdev, event, data);
+ mutex_lock_nested(&_rdev->mutex, lock_sublevel);
+ _notifier_call_chain(_rdev, event, data, lock_sublevel);
mutex_unlock(&_rdev->mutex);
}
}
@@ -2368,7 +2372,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
- _notifier_call_chain(rdev, event, data);
+ _notifier_call_chain(rdev, event, data, 0);
return NOTIFY_DONE;
}