The mei disconnect should be the last operation in remove flow.
Otherwise the device is used after destruction.
Fix minor free flow that happens after device destruction too.
The fault leads to the following oops in Intel Gfx CI:
<4>[ 267.871331] Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6bcb: 0000 [#1] SMP NOPTI
...
<4>[ 267.871410] RIP: 0010:mei_gsc_remove+0x44/0x90 [mei_gsc]
...
<4>[ 267.871555] Call Trace:
<4>[ 267.871562] <TASK>
<4>[ 267.871570] auxiliary_bus_remove+0x1b/0x30
<4>[ 267.871589] device_remove+0x43/0x80
<4>[ 267.871604] device_release_driver_internal+0x215/0x280
<4>[ 267.871619] device_release_driver+0x12/0x20
<4>[ 267.871630] bus_remove_device+0xdc/0x150
<4>[ 267.871645] device_del+0x15f/0x3b0
<4>[ 267.871656] ? bus_unregister_notifier+0x37/0x50
<4>[ 267.871672] gsc_destroy_one.isra.0+0x44/0x210 [i915]
<4>[ 267.872295] intel_gsc_fini+0x28/0x50 [i915]
<4>[ 267.872860] intel_gt_driver_unregister+0x2c/0x80 [i915]
<4>[ 267.873300] i915_driver_remove+0x6e/0x150 [i915]
<4>[ 267.873694] i915_pci_remove+0x1e/0x40 [i915]
<4>[ 267.874095] pci_device_remove+0x3e/0xb0
<4>[ 267.874111] device_remove+0x43/0x80
<4>[ 267.874126] device_release_driver_internal+0x215/0x280
<4>[ 267.874137] ? bus_find_device+0xa5/0xe0
<4>[ 267.874153] device_driver_detach+0x14/0x20
<4>[ 267.874164] unbind_store+0xac/0xc0
<4>[ 267.874178] drv_attr_store+0x21/0x50
<4>[ 267.874190] sysfs_kf_write+0x4a/0x80
<4>[ 267.874204] kernfs_fop_write_iter+0x188/0x240
<4>[ 267.874222] vfs_write+0x283/0x540
<4>[ 267.874241] ksys_write+0x6f/0xf0
<4>[ 267.874253] __x64_sys_write+0x19/0x30
<4>[ 267.874264] x64_sys_call+0x79/0x26a0
<4>[ 267.874277] do_syscall_64+0x93/0xd50
<4>[ 267.874291] ? do_syscall_64+0x1a2/0xd50
<4>[ 267.874301] ? do_syscall_64+0x1a2/0xd50
<4>[ 267.874313] ? do_syscall_64+0x1a2/0xd50
<4>[ 267.874324] ? clear_bhb_loop+0x30/0x80
<4>[ 267.874336] ? clear_bhb_loop+0x30/0x80
<4>[ 267.874349] entry_SYSCALL_64_after_hwframe+0x76/0x7e
Fixes: 7704e6be4ed2 ("mei: hook mei_device on class device")
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250915124554.2263330-1-alexander.usyskin@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
if (mei_me_hw_use_polling(hw))
kthread_stop(hw->polling_thread);
- mei_deregister(dev);
-
pm_runtime_disable(&aux_dev->dev);
mei_disable_interrupts(dev);
if (!mei_me_hw_use_polling(hw))
devm_free_irq(&aux_dev->dev, hw->irq, dev);
+
+ mei_deregister(dev);
}
static int __maybe_unused mei_gsc_pm_suspend(struct device *device)
/**
* mei_minor_free - mark device minor number as free
*
- * @dev: device pointer
+ * @minor: minor number to free
*/
-static void mei_minor_free(struct mei_device *dev)
+static void mei_minor_free(int minor)
{
mutex_lock(&mei_minor_lock);
- idr_remove(&mei_idr, dev->minor);
+ idr_remove(&mei_idr, minor);
mutex_unlock(&mei_minor_lock);
}
int mei_register(struct mei_device *dev, struct device *parent)
{
int ret, devno;
+ int minor;
ret = mei_minor_get(dev);
if (ret < 0)
return ret;
+ minor = dev->minor;
+
/* Fill in the data structures */
devno = MKDEV(MAJOR(mei_devt), dev->minor);
err_del_cdev:
cdev_del(dev->cdev);
err:
- mei_minor_free(dev);
+ mei_minor_free(minor);
return ret;
}
EXPORT_SYMBOL_GPL(mei_register);
void mei_deregister(struct mei_device *dev)
{
int devno;
+ int minor = dev->minor;
devno = dev->cdev->dev;
cdev_del(dev->cdev);
device_destroy(&mei_class, devno);
- mei_minor_free(dev);
+ mei_minor_free(minor);
}
EXPORT_SYMBOL_GPL(mei_deregister);