Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull core irq updates from Thomas Gleixner:
"The irq department delivers:
- Another tree wide update to get rid of the horrible create_irq
interface along with its even more horrible variants. That also
gets rid of the last leftovers of the initial sparse irq hackery.
arch/driver specific changes have been either acked or ignored.
- A fix for the spurious interrupt detection logic with threaded
interrupts.
- A new ARM SoC interrupt controller
- The usual pile of fixes and improvements all over the place"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits)
Documentation: brcmstb-l2: Add Broadcom STB Level-2 interrupt controller binding
irqchip: brcmstb-l2: Add Broadcom Set Top Box Level-2 interrupt controller
genirq: Improve documentation to match current implementation
ARM: iop13xx: fix msi support with sparse IRQ
genirq: Provide !SMP stub for irq_set_affinity_notifier()
irqchip: armada-370-xp: Move the devicetree binding documentation
irqchip: gic: Use mask field in GICC_IAR
genirq: Remove dynamic_irq mess
ia64: Use irq_init_desc
genirq: Replace dynamic_irq_init/cleanup
genirq: Remove irq_reserve_irq[s]
genirq: Replace reserve_irqs in core code
s390: Avoid call to irq_reserve_irqs()
s390: Remove pointless arch_show_interrupts()
s390: pci: Check return value of alloc_irq_desc() proper
sh: intc: Remove pointless irq_reserve_irqs() invocation
x86, irq: Remove pointless irq_reserve_irqs() call
genirq: Make create/destroy_irq() ia64 private
tile: Use SPARSE_IRQ
tile: pci: Use irq_alloc/free_hwirq()
...
This commit is contained in:
@@ -5,6 +5,10 @@ menu "IRQ subsystem"
|
||||
config MAY_HAVE_SPARSE_IRQ
|
||||
bool
|
||||
|
||||
# Legacy support, required for itanic
|
||||
config GENERIC_IRQ_LEGACY
|
||||
bool
|
||||
|
||||
# Enable the generic irq autoprobe mechanism
|
||||
config GENERIC_IRQ_PROBE
|
||||
bool
|
||||
@@ -17,6 +21,11 @@ config GENERIC_IRQ_SHOW
|
||||
config GENERIC_IRQ_SHOW_LEVEL
|
||||
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
|
||||
|
||||
+2
-3
@@ -40,10 +40,9 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip)
|
||||
irq_put_desc_unlock(desc, flags);
|
||||
/*
|
||||
* For !CONFIG_SPARSE_IRQ make the irq show up in
|
||||
* allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is
|
||||
* already marked, and this call is harmless.
|
||||
* allocated_irqs.
|
||||
*/
|
||||
irq_reserve_irq(irq);
|
||||
irq_mark_irq(irq);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(irq_set_chip);
|
||||
|
||||
@@ -33,7 +33,7 @@ enum {
|
||||
};
|
||||
|
||||
/*
|
||||
* Bit masks for desc->state
|
||||
* Bit masks for desc->core_internal_state__do_not_mess_with_it
|
||||
*
|
||||
* IRQS_AUTODETECT - autodetection in progress
|
||||
* IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt
|
||||
@@ -76,6 +76,12 @@ extern void mask_irq(struct irq_desc *desc);
|
||||
extern void unmask_irq(struct irq_desc *desc);
|
||||
extern void unmask_threaded_irq(struct irq_desc *desc);
|
||||
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
static inline void irq_mark_irq(unsigned int irq) { }
|
||||
#else
|
||||
extern void irq_mark_irq(unsigned int irq);
|
||||
#endif
|
||||
|
||||
extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
|
||||
|
||||
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action);
|
||||
|
||||
+63
-32
@@ -278,7 +278,12 @@ EXPORT_SYMBOL(irq_to_desc);
|
||||
|
||||
static void free_desc(unsigned int irq)
|
||||
{
|
||||
dynamic_irq_cleanup(irq);
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
desc_set_defaults(irq, desc, desc_node(desc), NULL);
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
|
||||
@@ -299,6 +304,20 @@ static int irq_expand_nr_irqs(unsigned int nr)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void irq_mark_irq(unsigned int irq)
|
||||
{
|
||||
mutex_lock(&sparse_irq_lock);
|
||||
bitmap_set(allocated_irqs, irq, 1);
|
||||
mutex_unlock(&sparse_irq_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_IRQ_LEGACY
|
||||
void irq_init_desc(unsigned int irq)
|
||||
{
|
||||
free_desc(irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !CONFIG_SPARSE_IRQ */
|
||||
|
||||
/**
|
||||
@@ -396,30 +415,56 @@ err:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__irq_alloc_descs);
|
||||
|
||||
#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
|
||||
/**
|
||||
* irq_reserve_irqs - mark irqs allocated
|
||||
* @from: mark from irq number
|
||||
* @cnt: number of irqs to mark
|
||||
* irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware
|
||||
* @cnt: number of interrupts to allocate
|
||||
* @node: node on which to allocate
|
||||
*
|
||||
* Returns 0 on success or an appropriate error code
|
||||
* Returns an interrupt number > 0 or 0, if the allocation fails.
|
||||
*/
|
||||
int irq_reserve_irqs(unsigned int from, unsigned int cnt)
|
||||
unsigned int irq_alloc_hwirqs(int cnt, int node)
|
||||
{
|
||||
unsigned int start;
|
||||
int ret = 0;
|
||||
int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL);
|
||||
|
||||
if (!cnt || (from + cnt) > nr_irqs)
|
||||
return -EINVAL;
|
||||
if (irq < 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sparse_irq_lock);
|
||||
start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0);
|
||||
if (start == from)
|
||||
bitmap_set(allocated_irqs, start, cnt);
|
||||
else
|
||||
ret = -EEXIST;
|
||||
mutex_unlock(&sparse_irq_lock);
|
||||
return ret;
|
||||
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;
|
||||
|
||||
for (i = from; cnt > 0; i++, cnt--) {
|
||||
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
|
||||
@@ -482,20 +527,6 @@ int irq_set_percpu_devid(unsigned int irq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dynamic_irq_cleanup - cleanup a dynamically allocated irq
|
||||
* @irq: irq number to initialize
|
||||
*/
|
||||
void dynamic_irq_cleanup(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
desc_set_defaults(irq, desc, desc_node(desc), NULL);
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
void kstat_incr_irq_this_cpu(unsigned int irq)
|
||||
{
|
||||
kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
|
||||
|
||||
@@ -27,14 +27,14 @@ static struct irq_domain *irq_default_domain;
|
||||
* __irq_domain_add() - Allocate a new irq_domain data structure
|
||||
* @of_node: optional device-tree node of the interrupt controller
|
||||
* @size: Size of linear map; 0 for radix mapping only
|
||||
* @hwirq_max: Maximum number of interrupts supported by controller
|
||||
* @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
|
||||
* direct mapping
|
||||
* @ops: map/unmap domain callbacks
|
||||
* @host_data: Controller private data pointer
|
||||
*
|
||||
* Allocates and initialize and irq_domain structure. Caller is expected to
|
||||
* register allocated irq_domain with irq_domain_register(). Returns pointer
|
||||
* to IRQ domain, or NULL on failure.
|
||||
* Allocates and initialize and irq_domain structure.
|
||||
* Returns pointer to IRQ domain, or NULL on failure.
|
||||
*/
|
||||
struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
|
||||
irq_hw_number_t hwirq_max, int direct_max,
|
||||
|
||||
+2
-2
@@ -886,8 +886,8 @@ static int irq_thread(void *data)
|
||||
irq_thread_check_affinity(desc, action);
|
||||
|
||||
action_ret = handler_fn(desc, action);
|
||||
if (!noirqdebug)
|
||||
note_interrupt(action->irq, desc, action_ret);
|
||||
if (action_ret == IRQ_HANDLED)
|
||||
atomic_inc(&desc->threads_handled);
|
||||
|
||||
wake_threads_waitq(desc);
|
||||
}
|
||||
|
||||
+102
-4
@@ -270,6 +270,8 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc,
|
||||
return action && (action->flags & IRQF_IRQPOLL);
|
||||
}
|
||||
|
||||
#define SPURIOUS_DEFERRED 0x80000000
|
||||
|
||||
void note_interrupt(unsigned int irq, struct irq_desc *desc,
|
||||
irqreturn_t action_ret)
|
||||
{
|
||||
@@ -277,15 +279,111 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
|
||||
irq_settings_is_polled(desc))
|
||||
return;
|
||||
|
||||
/* we get here again via the threaded handler */
|
||||
if (action_ret == IRQ_WAKE_THREAD)
|
||||
return;
|
||||
|
||||
if (bad_action_ret(action_ret)) {
|
||||
report_bad_irq(irq, desc, action_ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot call note_interrupt from the threaded handler
|
||||
* because we need to look at the compound of all handlers
|
||||
* (primary and threaded). Aside of that in the threaded
|
||||
* shared case we have no serialization against an incoming
|
||||
* hardware interrupt while we are dealing with a threaded
|
||||
* result.
|
||||
*
|
||||
* So in case a thread is woken, we just note the fact and
|
||||
* defer the analysis to the next hardware interrupt.
|
||||
*
|
||||
* The threaded handlers store whether they sucessfully
|
||||
* handled an interrupt and we check whether that number
|
||||
* changed versus the last invocation.
|
||||
*
|
||||
* We could handle all interrupts with the delayed by one
|
||||
* mechanism, but for the non forced threaded case we'd just
|
||||
* add pointless overhead to the straight hardirq interrupts
|
||||
* for the sake of a few lines less code.
|
||||
*/
|
||||
if (action_ret & IRQ_WAKE_THREAD) {
|
||||
/*
|
||||
* There is a thread woken. Check whether one of the
|
||||
* shared primary handlers returned IRQ_HANDLED. If
|
||||
* not we defer the spurious detection to the next
|
||||
* interrupt.
|
||||
*/
|
||||
if (action_ret == IRQ_WAKE_THREAD) {
|
||||
int handled;
|
||||
/*
|
||||
* We use bit 31 of thread_handled_last to
|
||||
* denote the deferred spurious detection
|
||||
* active. No locking necessary as
|
||||
* thread_handled_last is only accessed here
|
||||
* and we have the guarantee that hard
|
||||
* interrupts are not reentrant.
|
||||
*/
|
||||
if (!(desc->threads_handled_last & SPURIOUS_DEFERRED)) {
|
||||
desc->threads_handled_last |= SPURIOUS_DEFERRED;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Check whether one of the threaded handlers
|
||||
* returned IRQ_HANDLED since the last
|
||||
* interrupt happened.
|
||||
*
|
||||
* For simplicity we just set bit 31, as it is
|
||||
* set in threads_handled_last as well. So we
|
||||
* avoid extra masking. And we really do not
|
||||
* care about the high bits of the handled
|
||||
* count. We just care about the count being
|
||||
* different than the one we saw before.
|
||||
*/
|
||||
handled = atomic_read(&desc->threads_handled);
|
||||
handled |= SPURIOUS_DEFERRED;
|
||||
if (handled != desc->threads_handled_last) {
|
||||
action_ret = IRQ_HANDLED;
|
||||
/*
|
||||
* Note: We keep the SPURIOUS_DEFERRED
|
||||
* bit set. We are handling the
|
||||
* previous invocation right now.
|
||||
* Keep it for the current one, so the
|
||||
* next hardware interrupt will
|
||||
* account for it.
|
||||
*/
|
||||
desc->threads_handled_last = handled;
|
||||
} else {
|
||||
/*
|
||||
* None of the threaded handlers felt
|
||||
* responsible for the last interrupt
|
||||
*
|
||||
* We keep the SPURIOUS_DEFERRED bit
|
||||
* set in threads_handled_last as we
|
||||
* need to account for the current
|
||||
* interrupt as well.
|
||||
*/
|
||||
action_ret = IRQ_NONE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* One of the primary handlers returned
|
||||
* IRQ_HANDLED. So we don't care about the
|
||||
* threaded handlers on the same line. Clear
|
||||
* the deferred detection bit.
|
||||
*
|
||||
* In theory we could/should check whether the
|
||||
* deferred bit is set and take the result of
|
||||
* the previous run into account here as
|
||||
* well. But it's really not worth the
|
||||
* trouble. If every other interrupt is
|
||||
* handled we never trigger the spurious
|
||||
* detector. And if this is just the one out
|
||||
* of 100k unhandled ones which is handled
|
||||
* then we merily delay the spurious detection
|
||||
* by one hard interrupt. Not a real problem.
|
||||
*/
|
||||
desc->threads_handled_last &= ~SPURIOUS_DEFERRED;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(action_ret == IRQ_NONE)) {
|
||||
/*
|
||||
* If we are seeing only the odd spurious IRQ caused by
|
||||
|
||||
Reference in New Issue
Block a user