]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mei: me: trigger link reset if hw ready is unexpected
authorAlexander Usyskin <alexander.usyskin@intel.com>
Thu, 18 Sep 2025 13:04:31 +0000 (16:04 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Sep 2025 16:29:33 +0000 (18:29 +0200)
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
drivers/misc/mei/hw-me.c
drivers/misc/mei/init.c
drivers/misc/mei/mei_dev.h

index 346633ebc6e60d0c6dd257337129a1155dbbb957..3172dc095b53e098af1f91dc067bce23aa2d9d48 100644 (file)
@@ -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");
                }
index 4d1d5423b61267464f0c6967e1fa704399253635..b9fb54328a7b117cdba6e664dc6de5d297ee5a35 100644 (file)
@@ -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);
index 4ab2b9100fd4f4e27bcb40b3d6c04e24c4036327..9f2044ae6cc44d5093d99b1f9c97636565db6b79 100644 (file)
@@ -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,