mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Alexander Usyskin <alexander.usyskin@intel.com>
To: Arnd Bergmann <arnd@arndb.de>,
	 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-kernel@vger.kernel.org,
	 Alexander Usyskin <alexander.usyskin@intel.com>,
	 Menachem Adin <menachem.adin@intel.com>
Subject: [PATCH char-misc-next 3/4] mei: me: avoid hw access in polling when not active
Date: Mon, 31 Aug 2026 14:38:33 +0300	[thread overview]
Message-ID: <20260831-cri_polling-v1-3-d927315e6598@intel.com> (raw)
In-Reply-To: <20260831-cri_polling-v1-0-d927315e6598@intel.com>

Polling thread should not access hardware when not active.
Check for active state under device lock to avoid such
access when hardware is powered down.

Reviewed-by: Menachem Adin <menachem.adin@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/hw-me.c | 99 +++++++++++++++++++++++++++++-------------------
 1 file changed, 59 insertions(+), 40 deletions(-)

diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index ef7e1289ad7e..f3d833be0e1a 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -5,6 +5,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/cleanup.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/kthread.h>
@@ -1290,28 +1291,15 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
 }
 EXPORT_SYMBOL_GPL(mei_me_irq_quick_handler);
 
-/**
- * mei_me_irq_thread_handler - function called after ISR to handle the interrupt
- * processing.
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * Return: irqreturn_t
- *
- */
-irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
+static irqreturn_t __mei_me_irq_thread_handler(struct mei_device *dev)
 {
-	struct mei_device *dev = (struct mei_device *) dev_id;
 	struct list_head cmpl_list;
 	bool pg_blocked;
 	s32 slots;
 	u32 hcsr;
 	int rets = 0;
 
-	dev_dbg(&dev->dev, "function called after ISR to handle the interrupt processing.\n");
 	/* initialize our complete list */
-	mutex_lock(&dev->device_lock);
 
 	hcsr = mei_hcsr_read(dev);
 	me_intr_clear(dev, hcsr);
@@ -1406,13 +1394,33 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
 end:
 	dev_dbg(&dev->dev, "interrupt thread end ret = %d\n", rets);
 	mei_me_intr_enable(dev);
-	mutex_unlock(&dev->device_lock);
 	return IRQ_HANDLED;
 }
+
+/**
+ * mei_me_irq_thread_handler - function called after ISR to handle the interrupt
+ * processing.
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * Return: irqreturn_t
+ *
+ */
+irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
+{
+	struct mei_device *dev = (struct mei_device *) dev_id;
+
+	dev_dbg(&dev->dev, "function called after ISR to handle the interrupt processing.\n");
+
+	guard(mutex)(&dev->device_lock);
+
+	return __mei_me_irq_thread_handler(dev);
+}
 EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler);
 
-#define MEI_POLLING_TIMEOUT_ACTIVE 100
-#define MEI_POLLING_TIMEOUT_IDLE   500
+#define MEI_POLL_ACTIVE_MS 100
+#define MEI_POLL_IDLE_MS   500
 
 /**
  * mei_me_polling_thread - interrupt register polling thread
@@ -1420,48 +1428,59 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler);
  * @_dev: mei device
  *
  * The thread monitors the interrupt source register and calls
- * mei_me_irq_thread_handler() to handle the firmware
+ * __mei_me_irq_thread_handler() to handle the firmware
  * input.
  *
- * The function polls in MEI_POLLING_TIMEOUT_ACTIVE timeout
+ * The function polls in MEI_POLL_ACTIVE_MS timeout
  * in case there was an event, in idle case the polling
- * time increases yet again by MEI_POLLING_TIMEOUT_ACTIVE
- * up to MEI_POLLING_TIMEOUT_IDLE.
+ * time increases yet again by MEI_POLL_ACTIVE_MS
+ * up to MEI_POLL_IDLE_MS.
  *
  * Return: always 0
  */
 int mei_me_polling_thread(void *_dev)
 {
 	struct mei_device *dev = _dev;
-	irqreturn_t irq_ret;
-	long polling_timeout = MEI_POLLING_TIMEOUT_ACTIVE;
+	long polling_timeout = MEI_POLL_ACTIVE_MS;
+	bool have_interrupt;
 
 	dev_dbg(&dev->dev, "kernel thread is running\n");
 	while (!kthread_should_stop()) {
 		struct mei_me_hw *hw = to_me_hw(dev);
 		u32 hcsr;
 
-		wait_event_interruptible_timeout(hw->wait_active,
-						 hw->is_active || kthread_should_stop(),
-						 msecs_to_jiffies(MEI_POLLING_TIMEOUT_IDLE));
+		if (!hw->is_active)
+			wait_event_interruptible(hw->wait_active,
+						 hw->is_active || kthread_should_stop());
+		else
+			wait_event_interruptible_timeout(hw->wait_active,
+							 hw->is_active || kthread_should_stop(),
+							 msecs_to_jiffies(MEI_POLL_IDLE_MS));
 
 		if (kthread_should_stop())
 			break;
 
-		hcsr = mei_hcsr_read(dev);
-		if (me_intr_src(hcsr)) {
-			polling_timeout = MEI_POLLING_TIMEOUT_ACTIVE;
-			irq_ret = mei_me_irq_thread_handler(1, dev);
-			if (irq_ret != IRQ_HANDLED)
-				dev_err(&dev->dev, "irq_ret %d\n", irq_ret);
-		} else {
-			/*
-			 * Increase timeout by MEI_POLLING_TIMEOUT_ACTIVE
-			 * up to MEI_POLLING_TIMEOUT_IDLE
-			 */
-			polling_timeout = clamp_val(polling_timeout + MEI_POLLING_TIMEOUT_ACTIVE,
-						    MEI_POLLING_TIMEOUT_ACTIVE,
-						    MEI_POLLING_TIMEOUT_IDLE);
+		scoped_guard(mutex, &dev->device_lock) {
+			if (!hw->is_active) {
+				have_interrupt = false;
+			} else {
+				hcsr = mei_hcsr_read(dev);
+				have_interrupt = !!me_intr_src(hcsr);
+			}
+
+			if (have_interrupt) {
+				polling_timeout = MEI_POLL_ACTIVE_MS;
+				dev_dbg(&dev->dev, "polling interrupt processing\n");
+				__mei_me_irq_thread_handler(dev);
+			} else {
+				/*
+				 * Increase timeout by MEI_POLL_ACTIVE_MS
+				 * up to MEI_POLL_IDLE_MS
+				 */
+				polling_timeout = clamp_val(polling_timeout + MEI_POLL_ACTIVE_MS,
+							    MEI_POLL_ACTIVE_MS,
+							    MEI_POLL_IDLE_MS);
+			}
 		}
 
 		schedule_timeout_interruptible(msecs_to_jiffies(polling_timeout));

-- 
2.53.0


  parent reply	other threads:[~2026-08-31 11:38 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 11:38 [PATCH char-misc-next 0/4] mei: csc: add and enable polling option Alexander Usyskin
2026-08-31 11:38 ` [PATCH char-misc-next 1/4] mei: make polling wait interruptible Alexander Usyskin
2026-08-31 11:38 ` [PATCH char-misc-next 2/4] mei: csc: add option for polling and enable it Alexander Usyskin
2026-08-31 11:38 ` Alexander Usyskin [this message]
2026-08-31 11:38 ` [PATCH char-misc-next 4/4] mei: me: reduce active polling timeout to 20 ms Alexander Usyskin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260831-cri_polling-v1-3-d927315e6598@intel.com \
    --to=alexander.usyskin@intel.com \
    --cc=arnd@arndb.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=menachem.adin@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®