Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f38e87e8 authored by Ashutosh Dixit's avatar Ashutosh Dixit Committed by Greg Kroah-Hartman
Browse files

misc: mic: Fix crash when MIC reset is invoked in RESET_FAILED state



This patch fixes the following crash seen when MIC reset is invoked in
RESET_FAILED state due to device_del being called a second time on an
already deleted device:

[<ffffffff813b2295>] device_del+0x45/0x1d0
[<ffffffff813b243e>] device_unregister+0x1e/0x60
[<ffffffffa040f1c2>] scif_unregister_device+0x12/0x20 [scif_bus]
[<ffffffffa042f75a>] cosm_stop+0xaa/0xe0 [mic_cosm]
[<ffffffffa042f844>] cosm_reset_trigger_work+0x14/0x20 [mic_cosm]

The fix consists in realizing that because cosm_reset changes the
state to MIC_RESETTING, cosm_stop needs the previous state, before it
changed to MIC_RESETTING, to decide whether a hw_ops->stop had
previously been issued. This is now provided in a new cosm_device
member cdev->prev_state.

Reviewed-by: default avatarSudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: default avatarAshutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3f040887
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
 * @attr_group: Pointer to list of sysfs attribute groups.
 * @sdev: Device for sysfs entries.
 * @state: MIC state.
 * @prev_state: MIC state previous to MIC_RESETTING
 * @shutdown_status: MIC status reported by card for shutdown/crashes.
 * @shutdown_status_int: Internal shutdown status maintained by the driver
 * @cosm_mutex: Mutex for synchronizing access to data structures.
@@ -55,6 +56,7 @@ struct cosm_device {
	const struct attribute_group **attr_group;
	struct device *sdev;
	u8 state;
	u8 prev_state;
	u8 shutdown_status;
	u8 shutdown_status_int;
	struct mutex cosm_mutex;
+9 −4
Original line number Diff line number Diff line
@@ -153,8 +153,10 @@ void cosm_stop(struct cosm_device *cdev, bool force)
		 * stop(..) calls device_unregister and will crash the system if
		 * called multiple times.
		 */
		bool call_hw_ops = cdev->state != MIC_RESET_FAILED &&
					cdev->state != MIC_READY;
		u8 state = cdev->state == MIC_RESETTING ?
					cdev->prev_state : cdev->state;
		bool call_hw_ops = state != MIC_RESET_FAILED &&
					state != MIC_READY;

		if (cdev->state != MIC_RESETTING)
			cosm_set_state(cdev, MIC_RESETTING);
@@ -195,8 +197,11 @@ int cosm_reset(struct cosm_device *cdev)

	mutex_lock(&cdev->cosm_mutex);
	if (cdev->state != MIC_READY) {
		if (cdev->state != MIC_RESETTING) {
			cdev->prev_state = cdev->state;
			cosm_set_state(cdev, MIC_RESETTING);
			schedule_work(&cdev->reset_trigger_work);
		}
	} else {
		dev_err(&cdev->dev, "%s %d MIC is READY\n", __func__, __LINE__);
		rc = -EINVAL;