Commit 68be6c43 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman
Browse files

mei: gsc: fix remove operations order



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: 7704e6be ("mei: hook mei_device on class device")
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250915124554.2263330-1-alexander.usyskin@intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3ebcd346
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -150,13 +150,13 @@ static void mei_gsc_remove(struct auxiliary_device *aux_dev)
	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)
+9 −5
Original line number Diff line number Diff line
@@ -1208,12 +1208,12 @@ static int mei_minor_get(struct mei_device *dev)
/**
 * 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);
}

@@ -1225,11 +1225,14 @@ static void mei_device_release(struct device *dev)
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);

@@ -1279,7 +1282,7 @@ int mei_register(struct mei_device *dev, struct device *parent)
err_del_cdev:
	cdev_del(dev->cdev);
err:
	mei_minor_free(dev);
	mei_minor_free(minor);
	return ret;
}
EXPORT_SYMBOL_GPL(mei_register);
@@ -1287,6 +1290,7 @@ 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);
@@ -1295,7 +1299,7 @@ void mei_deregister(struct mei_device *dev)

	device_destroy(&mei_class, devno);

	mei_minor_free(dev);
	mei_minor_free(minor);
}
EXPORT_SYMBOL_GPL(mei_deregister);