提交 e3355c79 编写于 作者: T Thomas Gleixner 提交者: Yang Yingliang

genirq: Add return value to check_irq_resend()

mainline inclusion
from mainline-5.7
commit 1f85b1f5
category: bugfix
bugzilla: NA
CVE: NA

-------------------------------------------------

In preparation for an interrupt injection interface which can be used
safely by error injection mechanisms. e.g. PCI-E/ AER, add a return value
to check_irq_resend() so errors can be propagated to the caller.

Split out the software resend code so the ugly #ifdef in check_irq_resend()
goes away and the whole thing becomes readable.

Fix up the caller in debugfs. The caller in irq_startup() does not care
about the return value as this is unconditionally invoked for all
interrupts and the resend is best effort anyway.
Signed-off-by: NThomas Gleixner <tglx@linutronix.de>
Acked-by: NMarc Zyngier <maz@kernel.org>
Link: https://lkml.kernel.org/r/20200306130623.775200917@linutronix.deSigned-off-by: NLiao Chang <liaochang1@huawei.com>
Reviewed-by: NHanjun Guo <guohanjun@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 a8274e41
...@@ -218,8 +218,7 @@ static ssize_t irq_debug_write(struct file *file, const char __user *user_buf, ...@@ -218,8 +218,7 @@ static ssize_t irq_debug_write(struct file *file, const char __user *user_buf,
err = -EINVAL; err = -EINVAL;
} else { } else {
desc->istate |= IRQS_PENDING; desc->istate |= IRQS_PENDING;
check_irq_resend(desc); err = check_irq_resend(desc);
err = 0;
} }
raw_spin_unlock_irqrestore(&desc->lock, flags); raw_spin_unlock_irqrestore(&desc->lock, flags);
......
...@@ -108,7 +108,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc); ...@@ -108,7 +108,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc);
irqreturn_t handle_irq_event(struct irq_desc *desc); irqreturn_t handle_irq_event(struct irq_desc *desc);
/* Resending of interrupts :*/ /* Resending of interrupts :*/
void check_irq_resend(struct irq_desc *desc); int check_irq_resend(struct irq_desc *desc);
bool irq_wait_for_poll(struct irq_desc *desc); bool irq_wait_for_poll(struct irq_desc *desc);
void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action); void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
......
...@@ -47,6 +47,43 @@ static void resend_irqs(unsigned long arg) ...@@ -47,6 +47,43 @@ static void resend_irqs(unsigned long arg)
/* Tasklet to handle resend: */ /* Tasklet to handle resend: */
static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
static int irq_sw_resend(struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
/*
* Validate whether this interrupt can be safely injected from
* non interrupt context
*/
if (handle_enforce_irqctx(&desc->irq_data))
return -EINVAL;
/*
* If the interrupt is running in the thread context of the parent
* irq we need to be careful, because we cannot trigger it
* directly.
*/
if (irq_settings_is_nested_thread(desc)) {
/*
* If the parent_irq is valid, we retrigger the parent,
* otherwise we do nothing.
*/
if (!desc->parent_irq)
return -EINVAL;
irq = desc->parent_irq;
}
/* Set it pending and activate the softirq: */
set_bit(irq, irqs_resend);
tasklet_schedule(&resend_tasklet);
return 0;
}
#else
static int irq_sw_resend(struct irq_desc *desc)
{
return -EINVAL;
}
#endif #endif
static int try_retrigger(struct irq_desc *desc) static int try_retrigger(struct irq_desc *desc)
...@@ -66,48 +103,26 @@ static int try_retrigger(struct irq_desc *desc) ...@@ -66,48 +103,26 @@ static int try_retrigger(struct irq_desc *desc)
* *
* Is called with interrupts disabled and desc->lock held. * Is called with interrupts disabled and desc->lock held.
*/ */
void check_irq_resend(struct irq_desc *desc) int check_irq_resend(struct irq_desc *desc)
{ {
/* /*
* We do not resend level type interrupts. Level type * We do not resend level type interrupts. Level type interrupts
* interrupts are resent by hardware when they are still * are resent by hardware when they are still active. Clear the
* active. Clear the pending bit so suspend/resume does not * pending bit so suspend/resume does not get confused.
* get confused.
*/ */
if (irq_settings_is_level(desc)) { if (irq_settings_is_level(desc)) {
desc->istate &= ~IRQS_PENDING; desc->istate &= ~IRQS_PENDING;
return; return -EINVAL;
} }
if (desc->istate & IRQS_REPLAY) if (desc->istate & IRQS_REPLAY)
return; return -EBUSY;
if (desc->istate & IRQS_PENDING) { if (desc->istate & IRQS_PENDING) {
desc->istate &= ~IRQS_PENDING; desc->istate &= ~IRQS_PENDING;
desc->istate |= IRQS_REPLAY; desc->istate |= IRQS_REPLAY;
if (!try_retrigger(desc))
if (!try_retrigger(desc)) { return irq_sw_resend(desc);
#ifdef CONFIG_HARDIRQS_SW_RESEND
unsigned int irq = irq_desc_get_irq(desc);
/*
* If the interrupt is running in the thread
* context of the parent irq we need to be
* careful, because we cannot trigger it
* directly.
*/
if (irq_settings_is_nested_thread(desc)) {
/*
* If the parent_irq is valid, we
* retrigger the parent, otherwise we
* do nothing.
*/
if (!desc->parent_irq)
return;
irq = desc->parent_irq;
}
/* Set it pending and activate the softirq: */
set_bit(irq, irqs_resend);
tasklet_schedule(&resend_tasklet);
#endif
}
} }
return 0;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册