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: Sudeep Dutt <sudeep.dutt@intel.com> Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
3f040887a8
commit
f38e87e8c8
@ -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;
|
||||
|
@ -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) {
|
||||
cosm_set_state(cdev, MIC_RESETTING);
|
||||
schedule_work(&cdev->reset_trigger_work);
|
||||
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;
|
||||
|
Reference in New Issue
Block a user