summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Usyskin <alexander.usyskin@intel.com>2025-09-18 16:04:31 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-09-18 18:29:33 +0200
commit2cedb296988c384e1555d74fb55e3b7b9fb268ae (patch)
tree62e2686b9fce77ed2f54c80a6d872ec070854bf6
parent3ebcd3460cad351f198c39c6edb4af519a0ed934 (diff)
mei: me: trigger link reset if hw ready is unexpected
Driver can receive HW not ready interrupt unexpectedly. E.g. for cards that go donwn to D3cold. Trigger link reset in this case to synchronize driver and firmware state. No need to do that sync if driver is going down or interrupt is received before driver started initial link reset sequence. Introduce UNINITIALIZED device state to allow interrupt handler to ignore interrupts before first init. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://lore.kernel.org/r/20250918130435.3327400-2-alexander.usyskin@intel.com
-rw-r--r--drivers/misc/mei/hw-me.c17
-rw-r--r--drivers/misc/mei/init.c2
-rw-r--r--drivers/misc/mei/mei_dev.h3
3 files changed, 17 insertions, 5 deletions
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 346633ebc6e6..3172dc095b53 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -1373,9 +1373,20 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
- dev_dbg(&dev->dev, "we need to start the dev.\n");
- dev->recvd_hw_ready = true;
- wake_up(&dev->wait_hw_ready);
+ /* synchronized by dev mutex */
+ if (waitqueue_active(&dev->wait_hw_ready)) {
+ dev_dbg(&dev->dev, "we need to start the dev.\n");
+ dev->recvd_hw_ready = true;
+ wake_up(&dev->wait_hw_ready);
+ } else if (dev->dev_state != MEI_DEV_UNINITIALIZED &&
+ dev->dev_state != MEI_DEV_POWERING_DOWN &&
+ dev->dev_state != MEI_DEV_POWER_DOWN) {
+ dev_dbg(&dev->dev, "Force link reset.\n");
+ schedule_work(&dev->reset_work);
+ } else {
+ dev_dbg(&dev->dev, "Ignore this interrupt in state = %d\n",
+ dev->dev_state);
+ }
} else {
dev_dbg(&dev->dev, "Spurious Interrupt\n");
}
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 4d1d5423b612..b9fb54328a7b 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -399,7 +399,7 @@ void mei_device_init(struct mei_device *dev,
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_pg);
init_waitqueue_head(&dev->wait_hbm_start);
- dev->dev_state = MEI_DEV_INITIALIZING;
+ dev->dev_state = MEI_DEV_UNINITIALIZED;
dev->reset_count = 0;
INIT_LIST_HEAD(&dev->write_list);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 4ab2b9100fd4..9f2044ae6cc4 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -57,7 +57,8 @@ enum file_state {
/* MEI device states */
enum mei_dev_state {
- MEI_DEV_INITIALIZING = 0,
+ MEI_DEV_UNINITIALIZED = 0,
+ MEI_DEV_INITIALIZING,
MEI_DEV_INIT_CLIENTS,
MEI_DEV_ENABLED,
MEI_DEV_RESETTING,