Merge tag 'irq-core-2020-12-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner:
"Generic interrupt and irqchips subsystem updates. Unusually, there is
not a single completely new irq chip driver, just new DT bindings and
extensions of existing drivers to accomodate new variants!
Core:
- Consolidation and robustness changes for irq time accounting
- Cleanup and consolidation of irq stats
- Remove the fasteoi IPI flow which has been proved useless
- Provide an interface for converting legacy interrupt mechanism into
irqdomains
Drivers:
- Preliminary support for managed interrupts on platform devices
- Correctly identify allocation of MSIs proxyied by another device
- Generalise the Ocelot support to new SoCs
- Improve GICv4.1 vcpu entry, matching the corresponding KVM
optimisation
- Work around spurious interrupts on Qualcomm PDC
- Random fixes and cleanups"
* tag 'irq-core-2020-12-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (54 commits)
irqchip/qcom-pdc: Fix phantom irq when changing between rising/falling
driver core: platform: Add devm_platform_get_irqs_affinity()
ACPI: Drop acpi_dev_irqresource_disabled()
resource: Add irqresource_disabled()
genirq/affinity: Add irq_update_affinity_desc()
irqchip/gic-v3-its: Flag device allocation as proxied if behind a PCI bridge
irqchip/gic-v3-its: Tag ITS device as shared if allocating for a proxy device
platform-msi: Track shared domain allocation
irqchip/ti-sci-intr: Fix freeing of irqs
irqchip/ti-sci-inta: Fix printing of inta id on probe success
drivers/irqchip: Remove EZChip NPS interrupt controller
Revert "genirq: Add fasteoi IPI flow"
irqchip/hip04: Make IPIs use handle_percpu_devid_irq()
irqchip/bcm2836: Make IPIs use handle_percpu_devid_irq()
irqchip/armada-370-xp: Make IPIs use handle_percpu_devid_irq()
irqchip/gic, gic-v3: Make SGIs use handle_percpu_devid_irq()
irqchip/ocelot: Add support for Jaguar2 platforms
irqchip/ocelot: Add support for Serval platforms
irqchip/ocelot: Add support for Luton platforms
irqchip/ocelot: prepare to support more SoC
...
This commit is contained in:
@@ -26,11 +26,6 @@ config GENERIC_IRQ_SHOW_LEVEL
|
||||
config GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
bool
|
||||
|
||||
# Facility to allocate a hardware interrupt. This is legacy support
|
||||
# and should not be used in new code. Use irq domains instead.
|
||||
config GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
|
||||
bool
|
||||
|
||||
# Support for delayed migration from interrupt context
|
||||
config GENERIC_PENDING_IRQ
|
||||
bool
|
||||
|
||||
+1
-28
@@ -61,7 +61,7 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip)
|
||||
EXPORT_SYMBOL(irq_set_chip);
|
||||
|
||||
/**
|
||||
* irq_set_type - set the irq trigger type for an irq
|
||||
* irq_set_irq_type - set the irq trigger type for an irq
|
||||
* @irq: irq number
|
||||
* @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
|
||||
*/
|
||||
@@ -944,33 +944,6 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
|
||||
chip->irq_eoi(&desc->irq_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_percpu_devid_fasteoi_ipi - Per CPU local IPI handler with per cpu
|
||||
* dev ids
|
||||
* @desc: the interrupt description structure for this irq
|
||||
*
|
||||
* The biggest difference with the IRQ version is that the interrupt is
|
||||
* EOIed early, as the IPI could result in a context switch, and we need to
|
||||
* make sure the IPI can fire again. We also assume that the arch code has
|
||||
* registered an action. If not, we are positively doomed.
|
||||
*/
|
||||
void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct irqaction *action = desc->action;
|
||||
unsigned int irq = irq_desc_get_irq(desc);
|
||||
irqreturn_t res;
|
||||
|
||||
__kstat_incr_irqs_this_cpu(desc);
|
||||
|
||||
if (chip->irq_eoi)
|
||||
chip->irq_eoi(&desc->irq_data);
|
||||
|
||||
trace_irq_handler_entry(irq, action);
|
||||
res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
|
||||
trace_irq_handler_exit(irq, action, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_percpu_devid_fasteoi_nmi - Per CPU local NMI handler with per cpu
|
||||
* dev ids
|
||||
|
||||
@@ -269,7 +269,7 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
|
||||
}
|
||||
|
||||
/**
|
||||
* __irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
|
||||
* __irq_alloc_domain_generic_chips - Allocate generic chips for an irq domain
|
||||
* @d: irq domain for which to allocate chips
|
||||
* @irqs_per_chip: Number of interrupts each chip handles (max 32)
|
||||
* @num_ct: Number of irq_chip_type instances associated with this
|
||||
|
||||
@@ -810,57 +810,6 @@ unlock:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__irq_alloc_descs);
|
||||
|
||||
#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
|
||||
/**
|
||||
* irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware
|
||||
* @cnt: number of interrupts to allocate
|
||||
* @node: node on which to allocate
|
||||
*
|
||||
* Returns an interrupt number > 0 or 0, if the allocation fails.
|
||||
*/
|
||||
unsigned int irq_alloc_hwirqs(int cnt, int node)
|
||||
{
|
||||
int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL);
|
||||
|
||||
if (irq < 0)
|
||||
return 0;
|
||||
|
||||
for (i = irq; cnt > 0; i++, cnt--) {
|
||||
if (arch_setup_hwirq(i, node))
|
||||
goto err;
|
||||
irq_clear_status_flags(i, _IRQ_NOREQUEST);
|
||||
}
|
||||
return irq;
|
||||
|
||||
err:
|
||||
for (i--; i >= irq; i--) {
|
||||
irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE);
|
||||
arch_teardown_hwirq(i);
|
||||
}
|
||||
irq_free_descs(irq, cnt);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_alloc_hwirqs);
|
||||
|
||||
/**
|
||||
* irq_free_hwirqs - Free irq descriptor and cleanup the hardware
|
||||
* @from: Free from irq number
|
||||
* @cnt: number of interrupts to free
|
||||
*
|
||||
*/
|
||||
void irq_free_hwirqs(unsigned int from, int cnt)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = from, j = cnt; j > 0; i++, j--) {
|
||||
irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE);
|
||||
arch_teardown_hwirq(i);
|
||||
}
|
||||
irq_free_descs(from, cnt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_free_hwirqs);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* irq_get_next_irq - get next allocated irq number
|
||||
* @offset: where to start the search
|
||||
|
||||
+25
-7
@@ -359,17 +359,28 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
|
||||
irq_hw_number_t first_hwirq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
{
|
||||
return irq_domain_create_legacy(of_node_to_fwnode(of_node), size,
|
||||
first_irq, first_hwirq, ops, host_data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
|
||||
|
||||
struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
irq_hw_number_t first_hwirq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
|
||||
domain = __irq_domain_add(of_node_to_fwnode(of_node), first_hwirq + size,
|
||||
first_hwirq + size, 0, ops, host_data);
|
||||
domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
|
||||
if (domain)
|
||||
irq_domain_associate_many(domain, first_irq, first_hwirq, size);
|
||||
|
||||
return domain;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
|
||||
EXPORT_SYMBOL_GPL(irq_domain_create_legacy);
|
||||
|
||||
/**
|
||||
* irq_find_matching_fwspec() - Locates a domain for a given fwspec
|
||||
@@ -494,7 +505,7 @@ static void irq_domain_set_mapping(struct irq_domain *domain,
|
||||
}
|
||||
}
|
||||
|
||||
void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
|
||||
static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
|
||||
{
|
||||
struct irq_data *irq_data = irq_get_irq_data(irq);
|
||||
irq_hw_number_t hwirq;
|
||||
@@ -749,7 +760,7 @@ static void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
|
||||
{
|
||||
int i;
|
||||
|
||||
fwspec->fwnode = np ? &np->fwnode : NULL;
|
||||
fwspec->fwnode = of_node_to_fwnode(np);
|
||||
fwspec->param_count = count;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
@@ -1382,8 +1393,15 @@ static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain,
|
||||
unsigned int irq_base,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
if (domain->ops->free)
|
||||
domain->ops->free(domain, irq_base, nr_irqs);
|
||||
unsigned int i;
|
||||
|
||||
if (!domain->ops->free)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
if (irq_domain_get_irq_data(domain, irq_base + i))
|
||||
domain->ops->free(domain, irq_base + i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain,
|
||||
|
||||
@@ -371,6 +371,76 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_update_affinity_desc - Update affinity management for an interrupt
|
||||
* @irq: The interrupt number to update
|
||||
* @affinity: Pointer to the affinity descriptor
|
||||
*
|
||||
* This interface can be used to configure the affinity management of
|
||||
* interrupts which have been allocated already.
|
||||
*
|
||||
* There are certain limitations on when it may be used - attempts to use it
|
||||
* for when the kernel is configured for generic IRQ reservation mode (in
|
||||
* config GENERIC_IRQ_RESERVATION_MODE) will fail, as it may conflict with
|
||||
* managed/non-managed interrupt accounting. In addition, attempts to use it on
|
||||
* an interrupt which is already started or which has already been configured
|
||||
* as managed will also fail, as these mean invalid init state or double init.
|
||||
*/
|
||||
int irq_update_affinity_desc(unsigned int irq,
|
||||
struct irq_affinity_desc *affinity)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
unsigned long flags;
|
||||
bool activated;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Supporting this with the reservation scheme used by x86 needs
|
||||
* some more thought. Fail it for now.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
desc = irq_get_desc_buslock(irq, &flags, 0);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* Requires the interrupt to be shut down */
|
||||
if (irqd_is_started(&desc->irq_data)) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Interrupts which are already managed cannot be modified */
|
||||
if (irqd_affinity_is_managed(&desc->irq_data)) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deactivate the interrupt. That's required to undo
|
||||
* anything an earlier activation has established.
|
||||
*/
|
||||
activated = irqd_is_activated(&desc->irq_data);
|
||||
if (activated)
|
||||
irq_domain_deactivate_irq(&desc->irq_data);
|
||||
|
||||
if (affinity->is_managed) {
|
||||
irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED);
|
||||
irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN);
|
||||
}
|
||||
|
||||
cpumask_copy(desc->irq_common_data.affinity, &affinity->mask);
|
||||
|
||||
/* Restore the activation state */
|
||||
if (activated)
|
||||
irq_domain_activate_irq(&desc->irq_data, false);
|
||||
|
||||
out_unlock:
|
||||
irq_put_desc_busunlock(desc, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
+17
-19
@@ -44,12 +44,13 @@ static void irqtime_account_delta(struct irqtime *irqtime, u64 delta,
|
||||
}
|
||||
|
||||
/*
|
||||
* Called before incrementing preempt_count on {soft,}irq_enter
|
||||
* Called after incrementing preempt_count on {soft,}irq_enter
|
||||
* and before decrementing preempt_count on {soft,}irq_exit.
|
||||
*/
|
||||
void irqtime_account_irq(struct task_struct *curr)
|
||||
void irqtime_account_irq(struct task_struct *curr, unsigned int offset)
|
||||
{
|
||||
struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime);
|
||||
unsigned int pc;
|
||||
s64 delta;
|
||||
int cpu;
|
||||
|
||||
@@ -59,6 +60,7 @@ void irqtime_account_irq(struct task_struct *curr)
|
||||
cpu = smp_processor_id();
|
||||
delta = sched_clock_cpu(cpu) - irqtime->irq_start_time;
|
||||
irqtime->irq_start_time += delta;
|
||||
pc = preempt_count() - offset;
|
||||
|
||||
/*
|
||||
* We do not account for softirq time from ksoftirqd here.
|
||||
@@ -66,12 +68,11 @@ void irqtime_account_irq(struct task_struct *curr)
|
||||
* in that case, so as not to confuse scheduler with a special task
|
||||
* that do not consume any time, but still wants to run.
|
||||
*/
|
||||
if (hardirq_count())
|
||||
if (pc & HARDIRQ_MASK)
|
||||
irqtime_account_delta(irqtime, delta, CPUTIME_IRQ);
|
||||
else if (in_serving_softirq() && curr != this_cpu_ksoftirqd())
|
||||
else if ((pc & SOFTIRQ_OFFSET) && curr != this_cpu_ksoftirqd())
|
||||
irqtime_account_delta(irqtime, delta, CPUTIME_SOFTIRQ);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irqtime_account_irq);
|
||||
|
||||
static u64 irqtime_tick_accounted(u64 maxtime)
|
||||
{
|
||||
@@ -418,24 +419,21 @@ void vtime_task_switch(struct task_struct *prev)
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Archs that account the whole time spent in the idle task
|
||||
* (outside irq) as idle time can rely on this and just implement
|
||||
* vtime_account_kernel() and vtime_account_idle(). Archs that
|
||||
* have other meaning of the idle time (s390 only includes the
|
||||
* time spent by the CPU when it's in low power mode) must override
|
||||
* vtime_account().
|
||||
*/
|
||||
#ifndef __ARCH_HAS_VTIME_ACCOUNT
|
||||
void vtime_account_irq_enter(struct task_struct *tsk)
|
||||
void vtime_account_irq(struct task_struct *tsk, unsigned int offset)
|
||||
{
|
||||
if (!in_interrupt() && is_idle_task(tsk))
|
||||
unsigned int pc = preempt_count() - offset;
|
||||
|
||||
if (pc & HARDIRQ_OFFSET) {
|
||||
vtime_account_hardirq(tsk);
|
||||
} else if (pc & SOFTIRQ_OFFSET) {
|
||||
vtime_account_softirq(tsk);
|
||||
} else if (!IS_ENABLED(CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE) &&
|
||||
is_idle_task(tsk)) {
|
||||
vtime_account_idle(tsk);
|
||||
else
|
||||
} else {
|
||||
vtime_account_kernel(tsk);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
|
||||
#endif /* __ARCH_HAS_VTIME_ACCOUNT */
|
||||
|
||||
void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev,
|
||||
u64 *ut, u64 *st)
|
||||
|
||||
+63
-66
@@ -92,6 +92,13 @@ static bool ksoftirqd_running(unsigned long pending)
|
||||
!__kthread_should_park(tsk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
DEFINE_PER_CPU(int, hardirqs_enabled);
|
||||
DEFINE_PER_CPU(int, hardirq_context);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* preempt_count and SOFTIRQ_OFFSET usage:
|
||||
* - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
|
||||
@@ -102,17 +109,11 @@ static bool ksoftirqd_running(unsigned long pending)
|
||||
* softirq and whether we just have bh disabled.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This one is for softirq.c-internal use,
|
||||
* where hardirqs are disabled legitimately:
|
||||
*/
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
|
||||
DEFINE_PER_CPU(int, hardirqs_enabled);
|
||||
DEFINE_PER_CPU(int, hardirq_context);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
|
||||
|
||||
/*
|
||||
* This is for softirq.c-internal use, where hardirqs are disabled
|
||||
* legitimately:
|
||||
*/
|
||||
void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -203,6 +204,50 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
|
||||
}
|
||||
EXPORT_SYMBOL(__local_bh_enable_ip);
|
||||
|
||||
static inline void invoke_softirq(void)
|
||||
{
|
||||
if (ksoftirqd_running(local_softirq_pending()))
|
||||
return;
|
||||
|
||||
if (!force_irqthreads) {
|
||||
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||
/*
|
||||
* We can safely execute softirq on the current stack if
|
||||
* it is the irq stack, because it should be near empty
|
||||
* at this stage.
|
||||
*/
|
||||
__do_softirq();
|
||||
#else
|
||||
/*
|
||||
* Otherwise, irq_exit() is called on the task stack that can
|
||||
* be potentially deep already. So call softirq in its own stack
|
||||
* to prevent from any overrun.
|
||||
*/
|
||||
do_softirq_own_stack();
|
||||
#endif
|
||||
} else {
|
||||
wakeup_softirqd();
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage __visible void do_softirq(void)
|
||||
{
|
||||
__u32 pending;
|
||||
unsigned long flags;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
pending = local_softirq_pending();
|
||||
|
||||
if (pending && !ksoftirqd_running(pending))
|
||||
do_softirq_own_stack();
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* We restart softirq processing for at most MAX_SOFTIRQ_RESTART times,
|
||||
* but break the loop if need_resched() is set or after 2 ms.
|
||||
@@ -270,10 +315,10 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
|
||||
current->flags &= ~PF_MEMALLOC;
|
||||
|
||||
pending = local_softirq_pending();
|
||||
account_irq_enter_time(current);
|
||||
|
||||
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
|
||||
in_hardirq = lockdep_softirq_start();
|
||||
account_softirq_enter(current);
|
||||
|
||||
restart:
|
||||
/* Reset the pending bitmask before enabling irqs */
|
||||
@@ -320,46 +365,24 @@ restart:
|
||||
wakeup_softirqd();
|
||||
}
|
||||
|
||||
account_softirq_exit(current);
|
||||
lockdep_softirq_end(in_hardirq);
|
||||
account_irq_exit_time(current);
|
||||
__local_bh_enable(SOFTIRQ_OFFSET);
|
||||
WARN_ON_ONCE(in_interrupt());
|
||||
current_restore_flags(old_flags, PF_MEMALLOC);
|
||||
}
|
||||
|
||||
asmlinkage __visible void do_softirq(void)
|
||||
{
|
||||
__u32 pending;
|
||||
unsigned long flags;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
pending = local_softirq_pending();
|
||||
|
||||
if (pending && !ksoftirqd_running(pending))
|
||||
do_softirq_own_stack();
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_enter_rcu - Enter an interrupt context with RCU watching
|
||||
*/
|
||||
void irq_enter_rcu(void)
|
||||
{
|
||||
if (is_idle_task(current) && !in_interrupt()) {
|
||||
/*
|
||||
* Prevent raise_softirq from needlessly waking up ksoftirqd
|
||||
* here, as softirq will be serviced on return from interrupt.
|
||||
*/
|
||||
local_bh_disable();
|
||||
__irq_enter_raw();
|
||||
|
||||
if (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))
|
||||
tick_irq_enter();
|
||||
_local_bh_enable();
|
||||
}
|
||||
__irq_enter();
|
||||
|
||||
account_hardirq_enter(current);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,32 +394,6 @@ void irq_enter(void)
|
||||
irq_enter_rcu();
|
||||
}
|
||||
|
||||
static inline void invoke_softirq(void)
|
||||
{
|
||||
if (ksoftirqd_running(local_softirq_pending()))
|
||||
return;
|
||||
|
||||
if (!force_irqthreads) {
|
||||
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||
/*
|
||||
* We can safely execute softirq on the current stack if
|
||||
* it is the irq stack, because it should be near empty
|
||||
* at this stage.
|
||||
*/
|
||||
__do_softirq();
|
||||
#else
|
||||
/*
|
||||
* Otherwise, irq_exit() is called on the task stack that can
|
||||
* be potentially deep already. So call softirq in its own stack
|
||||
* to prevent from any overrun.
|
||||
*/
|
||||
do_softirq_own_stack();
|
||||
#endif
|
||||
} else {
|
||||
wakeup_softirqd();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tick_irq_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_NO_HZ_COMMON
|
||||
@@ -417,7 +414,7 @@ static inline void __irq_exit_rcu(void)
|
||||
#else
|
||||
lockdep_assert_irqs_disabled();
|
||||
#endif
|
||||
account_irq_exit_time(current);
|
||||
account_hardirq_exit(current);
|
||||
preempt_count_sub(HARDIRQ_OFFSET);
|
||||
if (!in_interrupt() && local_softirq_pending())
|
||||
invoke_softirq();
|
||||
|
||||
Reference in New Issue
Block a user