Re: [char-misc-next] mei: hook mei_device on class device

From: Guenter Roeck
Date: Sun Nov 02 2025 - 12:54:08 EST


On 11/2/25 07:37, Guenter Roeck wrote:
On Sun, Nov 2, 2025 at 7:00 AM Usyskin, Alexander <linux@xxxxxxxxxxxx> wrote:

That got messed up. Sorry for that. Really sending to Alexander this time.

Guenter

...

Seems I've missed the error flow in probe (my test machines always have an ME in a good state...).

Below patch should fix the problem, can you confirm?

Yes, it does. With this patch applied, the log output is:

...
[ 16.406790] mtdoops: mtd device (mtddev=name/number) must be supplied
[ 18.380400] mei mei0: wait hw ready failed
[ 18.384594] mei mei0: hw_start failed ret = -62 fw status =
00070355 002F0006 00000000 00000000 00000000 00000000
[ 20.428395] mei mei0: wait hw ready failed
[ 20.432542] mei mei0: hw_start failed ret = -62 fw status =
00070355 002F0006 00000000 00000000 00000000 00000000
[ 22.476390] mei mei0: wait hw ready failed
[ 22.480533] mei mei0: hw_start failed ret = -62 fw status =
00070355 002F0006 00000000 00000000 00000000 00000000
[ 22.490847] mei mei0: reset: reached maximal consecutive resets:
disabling the device
[ 22.498718] mei mei0: reset failed ret = -19
[ 22.503012] mei mei0: link layer initialization failed.
[ 22.508261] mei_me 0000:00:16.0: init hw failure.
[ 22.513662] mei_me 0000:00:16.0: initialization failed.
initramfs(out): Mounting system filesystems for initramfs init.d
...

Official Tested-by: tag below. Note that it is from my Google address
since this is where I tested the fix.

Thanks a lot for the quick turnaround!

Guenter

From c58f311df60f26df2efe1e0f9fc523bfa4b93936 Mon Sep 17 00:00:00 2001
From: Alexander Usyskin <alexander.usyskin@xxxxxxxxx>
Date: Sun, 2 Nov 2025 10:57:22 +0200
Subject: [PATCH] mei: fix error flow in probe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Dismantle class device last in probe error flow to avoid accessing freed memory like:

[ 87.926774] WARNING: CPU: 9 PID: 518 at kernel/workqueue.c:4234
__flush_work+0x340/0x390
...
[ 87.926912] Workqueue: async async_run_entry_fn
[ 87.926918] RIP: e030:__flush_work+0x340/0x390
[ 87.926923] Code: 26 9d 05 00 65 48 8b 15 26 3c ca 02 48 85 db 48 8b
04 24 48 89 54 24 58 0f 85 de fe ff ff e9 f6 fd ff ff 0f 0b e9 77 ff ff
ff <0f> 0b e9 70 ff ff ff 0f 0b e9 19 ff ff ff e8 7d 8b 0e 01 48 89 de
[ 87.926931] RSP: e02b:ffffc900412ebc00 EFLAGS: 00010246
[ 87.926936] RAX: 0000000000000000 RBX: ffff888103e55090 RCX: 0000000000000000
[ 87.926941] RDX: 000fffffffe00000 RSI: 0000000000000001 RDI: ffffc900412ebc60
[ 87.926945] RBP: ffff888103e55090 R08: ffffffffc1266ec8 R09: ffff8881109076e8
[ 87.926949] R10: 0000000080040003 R11: 0000000000000000 R12: ffff888103e54000
[ 87.926953] R13: ffffc900412ebc18 R14: 0000000000000001 R15: 0000000000000000
[ 87.926962] FS: 0000000000000000(0000) GS:ffff888233238000(0000) knlGS:0000000000000000
[ 87.926967] CS: e030 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 87.926971] CR2: 00007e7923b32708 CR3: 00000001088df000 CR4: 0000000000050660
[ 87.926977] Call Trace:
[ 87.926981] <TASK>
[ 87.926987] ? __call_rcu_common.constprop.0+0x11e/0x310
[ 87.926993] cancel_work_sync+0x5e/0x80
[ 87.926999] mei_cancel_work+0x19/0x40 [mei]
[ 87.927051] mei_me_probe+0x273/0x2b0 [mei_me]
[ 87.927060] local_pci_probe+0x45/0x90
[ 87.927066] pci_call_probe+0x5b/0x180
[ 87.927070] pci_device_probe+0x95/0x140
[ 87.927074] ? driver_sysfs_add+0x57/0xc0
[ 87.927079] really_probe+0xde/0x340
[ 87.927083] ? pm_runtime_barrier+0x54/0x90
[ 87.927087] __driver_probe_device+0x78/0x110
[ 87.927092] driver_probe_device+0x1f/0xa0
[ 87.927095] __driver_attach_async_helper+0x5e/0xe0
[ 87.927100] async_run_entry_fn+0x34/0x130
[ 87.927104] process_one_work+0x18d/0x340
[ 87.927108] worker_thread+0x256/0x3a0
[ 87.927111] ? __pfx_worker_thread+0x10/0x10
[ 87.927115] kthread+0xfc/0x240
[ 87.927120] ? __pfx_kthread+0x10/0x10
[ 87.927124] ? __pfx_kthread+0x10/0x10
[ 87.927127] ret_from_fork+0xf5/0x110
[ 87.927132] ? __pfx_kthread+0x10/0x10
[ 87.927136] ret_from_fork_asm+0x1a/0x30
[ 87.927141] </TASK>

Reported-by: Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
Reported-by: Guenter Roeck <linux@xxxxxxxxxxxx>
Fixes: 7704e6be4ed2 ("mei: hook mei_device on class device")
Signed-off-by: Alexander Usyskin <alexander.usyskin@xxxxxxxxx>

Tested-by: Guenter Roeck <groeck@xxxxxxxxxx>


---
drivers/misc/mei/pci-me.c | 13 ++++++-------
drivers/misc/mei/pci-txe.c | 13 ++++++-------
drivers/misc/mei/platform-vsc.c | 11 +++++------
3 files changed, 17 insertions(+), 20 deletions(-)

diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index b017ff29dbd1..73cad914be9f 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -223,6 +223,10 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->mem_addr = pcim_iomap_table(pdev)[0];
hw->read_fws = mei_me_read_fws;

+ err = mei_register(dev, &pdev->dev);
+ if (err)
+ goto end;
+
pci_enable_msi(pdev);

hw->irq = pdev->irq;
@@ -237,13 +241,9 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) {
dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
pdev->irq);
- goto end;
+ goto deregister;
}

- err = mei_register(dev, &pdev->dev);
- if (err)
- goto release_irq;
-
if (mei_start(dev)) {
dev_err(&pdev->dev, "init hw failure.\n");
err = -ENODEV;
@@ -283,11 +283,10 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;

deregister:
- mei_deregister(dev);
-release_irq:
mei_cancel_work(dev);
mei_disable_interrupts(dev);
free_irq(pdev->irq, dev);
+ mei_deregister(dev);
end:
dev_err(&pdev->dev, "initialization failed.\n");
return err;
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index 06b55a891c6b..98d1bc2c7f4b 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -87,6 +87,10 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw = to_txe_hw(dev);
hw->mem_addr = pcim_iomap_table(pdev);

+ err = mei_register(dev, &pdev->dev);
+ if (err)
+ goto end;
+
pci_enable_msi(pdev);

/* clear spurious interrupts */
@@ -106,13 +110,9 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) {
dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
pdev->irq);
- goto end;
+ goto deregister;
}

- err = mei_register(dev, &pdev->dev);
- if (err)
- goto release_irq;
-
if (mei_start(dev)) {
dev_err(&pdev->dev, "init hw failure.\n");
err = -ENODEV;
@@ -145,11 +145,10 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;

deregister:
- mei_deregister(dev);
-release_irq:
mei_cancel_work(dev);
mei_disable_interrupts(dev);
free_irq(pdev->irq, dev);
+ mei_deregister(dev);
end:
dev_err(&pdev->dev, "initialization failed.\n");
return err;
diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c
index 288e7b72e942..9787b9cee71c 100644
--- a/drivers/misc/mei/platform-vsc.c
+++ b/drivers/misc/mei/platform-vsc.c
@@ -362,28 +362,27 @@ static int mei_vsc_probe(struct platform_device *pdev)

ret = mei_register(mei_dev, dev);
if (ret)
- goto err_dereg;
+ goto err;

ret = mei_start(mei_dev);
if (ret) {
dev_err_probe(dev, ret, "init hw failed\n");
- goto err_cancel;
+ goto err;
}

pm_runtime_enable(mei_dev->parent);

return 0;

-err_dereg:
- mei_deregister(mei_dev);
-
-err_cancel:
+err:
mei_cancel_work(mei_dev);

vsc_tp_register_event_cb(tp, NULL, NULL);

mei_disable_interrupts(mei_dev);

+ mei_deregister(mei_dev);
+
return ret;
}

--
2.43.0