mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
mei: me: avoid hw access in polling when not active
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> Link: https://patch.msgid.link/20260831-cri_polling-v1-3-d927315e6598@intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
155c978d1b
commit
528f61bdc5
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user