mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-24 13:44:26 -04:00
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull genirq updates from Thomas Gleixner:
"The irq departement provides:
- A synchronization fix for free_irq() to synchronize just the
removed interrupt thread on shared interrupt lines.
- Consolidate the multi low level interrupt entry handling and mvoe
it to the generic code instead of adding yet another copy for
RISC-V
- Refactoring of the ARM LPI allocator and LPI exposure to the
hypervisor
- Yet another interrupt chip driver for the JZ4725B SoC
- Speed up for /proc/interrupts as people seem to love reading this
file with high frequency
- Miscellaneous fixes and updates"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
irqchip/gic-v3-its: Make its_lock a raw_spin_lock_t
genirq/irqchip: Remove MULTI_IRQ_HANDLER as it's now obselete
openrisc: Use the new GENERIC_IRQ_MULTI_HANDLER
arm64: Use the new GENERIC_IRQ_MULTI_HANDLER
ARM: Convert to GENERIC_IRQ_MULTI_HANDLER
irqchip: Port the ARM IRQ drivers to GENERIC_IRQ_MULTI_HANDLER
irqchip/gic-v3-its: Reduce minimum LPI allocation to 1 for PCI devices
dt-bindings: irqchip: renesas-irqc: Document r8a77980 support
dt-bindings: irqchip: renesas-irqc: Document r8a77470 support
irqchip/ingenic: Add support for the JZ4725B SoC
irqchip/stm32: Add exti0 translation for stm32mp1
genirq: Remove redundant NULL pointer check in __free_irq()
irqchip/gic-v3-its: Honor hypervisor enforced LPI range
irqchip/gic-v3: Expose GICD_TYPER in the rdist structure
irqchip/gic-v3-its: Drop chunk allocation compatibility
irqchip/gic-v3-its: Move minimum LPI requirements to individual busses
irqchip/gic-v3-its: Use full range of LPIs
irqchip/gic-v3-its: Refactor LPI allocator
genirq: Synchronize only with single thread on free_irq()
genirq: Update code comments wrt recycled thread_mask
...
This commit is contained in:
commit
d0daaeaf60
27 changed files with 251 additions and 202 deletions
|
|
@ -134,7 +134,6 @@ config GENERIC_IRQ_DEBUGFS
|
|||
endmenu
|
||||
|
||||
config GENERIC_IRQ_MULTI_HANDLER
|
||||
depends on !MULTI_IRQ_HANDLER
|
||||
bool
|
||||
help
|
||||
Allow to specify the low level IRQ handler at run time.
|
||||
|
|
|
|||
|
|
@ -443,6 +443,7 @@ static void free_desc(unsigned int irq)
|
|||
* We free the descriptor, masks and stat fields via RCU. That
|
||||
* allows demultiplex interrupts to do rcu based management of
|
||||
* the child interrupts.
|
||||
* This also allows us to use rcu in kstat_irqs_usr().
|
||||
*/
|
||||
call_rcu(&desc->rcu, delayed_free_desc);
|
||||
}
|
||||
|
|
@ -928,17 +929,17 @@ unsigned int kstat_irqs(unsigned int irq)
|
|||
* kstat_irqs_usr - Get the statistics for an interrupt
|
||||
* @irq: The interrupt number
|
||||
*
|
||||
* Returns the sum of interrupt counts on all cpus since boot for
|
||||
* @irq. Contrary to kstat_irqs() this can be called from any
|
||||
* preemptible context. It's protected against concurrent removal of
|
||||
* an interrupt descriptor when sparse irqs are enabled.
|
||||
* Returns the sum of interrupt counts on all cpus since boot for @irq.
|
||||
* Contrary to kstat_irqs() this can be called from any context.
|
||||
* It uses rcu since a concurrent removal of an interrupt descriptor is
|
||||
* observing an rcu grace period before delayed_free_desc()/irq_kobj_release().
|
||||
*/
|
||||
unsigned int kstat_irqs_usr(unsigned int irq)
|
||||
{
|
||||
unsigned int sum;
|
||||
|
||||
irq_lock_sparse();
|
||||
rcu_read_lock();
|
||||
sum = kstat_irqs(irq);
|
||||
irq_unlock_sparse();
|
||||
rcu_read_unlock();
|
||||
return sum;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -790,9 +790,19 @@ static irqreturn_t irq_forced_secondary_handler(int irq, void *dev_id)
|
|||
|
||||
static int irq_wait_for_interrupt(struct irqaction *action)
|
||||
{
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
if (kthread_should_stop()) {
|
||||
/* may need to run one last time */
|
||||
if (test_and_clear_bit(IRQTF_RUNTHREAD,
|
||||
&action->thread_flags)) {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(IRQTF_RUNTHREAD,
|
||||
&action->thread_flags)) {
|
||||
|
|
@ -800,10 +810,7 @@ static int irq_wait_for_interrupt(struct irqaction *action)
|
|||
return 0;
|
||||
}
|
||||
schedule();
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1024,11 +1031,8 @@ static int irq_thread(void *data)
|
|||
/*
|
||||
* This is the regular exit path. __free_irq() is stopping the
|
||||
* thread via kthread_stop() after calling
|
||||
* synchronize_irq(). So neither IRQTF_RUNTHREAD nor the
|
||||
* oneshot mask bit can be set. We cannot verify that as we
|
||||
* cannot touch the oneshot mask at this point anymore as
|
||||
* __setup_irq() might have given out currents thread_mask
|
||||
* again.
|
||||
* synchronize_hardirq(). So neither IRQTF_RUNTHREAD nor the
|
||||
* oneshot mask bit can be set.
|
||||
*/
|
||||
task_work_cancel(current, irq_thread_dtor);
|
||||
return 0;
|
||||
|
|
@ -1251,8 +1255,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
|
|||
|
||||
/*
|
||||
* Protects against a concurrent __free_irq() call which might wait
|
||||
* for synchronize_irq() to complete without holding the optional
|
||||
* chip bus lock and desc->lock.
|
||||
* for synchronize_hardirq() to complete without holding the optional
|
||||
* chip bus lock and desc->lock. Also protects against handing out
|
||||
* a recycled oneshot thread_mask bit while it's still in use by
|
||||
* its previous owner.
|
||||
*/
|
||||
mutex_lock(&desc->request_mutex);
|
||||
|
||||
|
|
@ -1571,9 +1577,6 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
|
|||
|
||||
WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
|
||||
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&desc->request_mutex);
|
||||
chip_bus_lock(desc);
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
|
|
@ -1620,11 +1623,11 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
|
|||
/*
|
||||
* Drop bus_lock here so the changes which were done in the chip
|
||||
* callbacks above are synced out to the irq chips which hang
|
||||
* behind a slow bus (I2C, SPI) before calling synchronize_irq().
|
||||
* behind a slow bus (I2C, SPI) before calling synchronize_hardirq().
|
||||
*
|
||||
* Aside of that the bus_lock can also be taken from the threaded
|
||||
* handler in irq_finalize_oneshot() which results in a deadlock
|
||||
* because synchronize_irq() would wait forever for the thread to
|
||||
* because kthread_stop() would wait forever for the thread to
|
||||
* complete, which is blocked on the bus lock.
|
||||
*
|
||||
* The still held desc->request_mutex() protects against a
|
||||
|
|
@ -1636,7 +1639,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
|
|||
unregister_handler_proc(irq, action);
|
||||
|
||||
/* Make sure it's not being used on another CPU: */
|
||||
synchronize_irq(irq);
|
||||
synchronize_hardirq(irq);
|
||||
|
||||
#ifdef CONFIG_DEBUG_SHIRQ
|
||||
/*
|
||||
|
|
@ -1645,7 +1648,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
|
|||
* is so by doing an extra call to the handler ....
|
||||
*
|
||||
* ( We do this after actually deregistering it, to make sure that a
|
||||
* 'real' IRQ doesn't run in * parallel with our fake. )
|
||||
* 'real' IRQ doesn't run in parallel with our fake. )
|
||||
*/
|
||||
if (action->flags & IRQF_SHARED) {
|
||||
local_irq_save(flags);
|
||||
|
|
@ -1654,6 +1657,12 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The action has already been removed above, but the thread writes
|
||||
* its oneshot mask bit when it completes. Though request_mutex is
|
||||
* held across this which prevents __setup_irq() from handing out
|
||||
* the same bit to a newly requested action.
|
||||
*/
|
||||
if (action->thread) {
|
||||
kthread_stop(action->thread);
|
||||
put_task_struct(action->thread);
|
||||
|
|
|
|||
|
|
@ -475,22 +475,24 @@ int show_interrupts(struct seq_file *p, void *v)
|
|||
seq_putc(p, '\n');
|
||||
}
|
||||
|
||||
irq_lock_sparse();
|
||||
rcu_read_lock();
|
||||
desc = irq_to_desc(i);
|
||||
if (!desc)
|
||||
goto outsparse;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
for_each_online_cpu(j)
|
||||
any_count |= kstat_irqs_cpu(i, j);
|
||||
action = desc->action;
|
||||
if ((!action || irq_desc_is_chained(desc)) && !any_count)
|
||||
goto out;
|
||||
if (desc->kstat_irqs)
|
||||
for_each_online_cpu(j)
|
||||
any_count |= *per_cpu_ptr(desc->kstat_irqs, j);
|
||||
|
||||
if ((!desc->action || irq_desc_is_chained(desc)) && !any_count)
|
||||
goto outsparse;
|
||||
|
||||
seq_printf(p, "%*d: ", prec, i);
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
|
||||
seq_printf(p, "%10u ", desc->kstat_irqs ?
|
||||
*per_cpu_ptr(desc->kstat_irqs, j) : 0);
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
if (desc->irq_data.chip) {
|
||||
if (desc->irq_data.chip->irq_print_chip)
|
||||
desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
|
||||
|
|
@ -511,6 +513,7 @@ int show_interrupts(struct seq_file *p, void *v)
|
|||
if (desc->name)
|
||||
seq_printf(p, "-%-8s", desc->name);
|
||||
|
||||
action = desc->action;
|
||||
if (action) {
|
||||
seq_printf(p, " %s", action->name);
|
||||
while ((action = action->next) != NULL)
|
||||
|
|
@ -518,10 +521,9 @@ int show_interrupts(struct seq_file *p, void *v)
|
|||
}
|
||||
|
||||
seq_putc(p, '\n');
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
outsparse:
|
||||
irq_unlock_sparse();
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue