diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2010-09-27 11:48:26 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-10-12 10:39:07 -0400 |
commit | 1f5a5b87f78fade3ae48dfd55e8765d1d622ea4e (patch) | |
tree | 762a5dbf40129ffd9667a170b2503a77c95320f7 /include/linux | |
parent | 1318a481fc37c503a901b96ae06b692ca2b21af5 (diff) |
genirq: Implement a sane sparse_irq allocator
The current sparse_irq allocator has several short comings due to
failures in the design or the lack of it:
- Requires iteration over the number of active irqs to find a free slot
(Some architectures have grown their own workarounds for this)
- Removal of entries is not possible
- Racy between create_irq_nr and destroy_irq (plugged by horrible
callbacks)
- Migration of active irq descriptors is not possible
- No bulk allocation of irq ranges
- Sprinkeled irq_desc references all over the place outside of kernel/irq/
(The previous chip functions series is addressing this issue)
Implement a sane allocator which fixes the above short comings (though
migration of active descriptors needs a full tree wide cleanup of the
direct and mostly unlocked access to irq_desc).
The new allocator still uses a radix_tree, but uses a bitmap for
keeping track of allocated irq numbers. That allows:
- Fast lookup of a free slot
- Allows the removal of descriptors
- Prevents the create/destroy race
- Bulk allocation of consecutive irq ranges
- Basic design is ready for migration of life descriptors after
further cleanups
The bitmap is also used in the SPARSE_IRQ=n case for lookup and
raceless (de)allocation of irq numbers. So it removes the requirement
for looping through the descriptor array to find slots.
Right now it uses sparse_irq_lock to protect the bitmap and the radix
tree, but after cleaning up all users we should be able convert that
to a mutex and to switch the radix_tree and decriptor allocations to
GFP_KERNEL.
[ Folded in a bugfix from Yinghai Lu ]
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/irq.h | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h index 30a300991ed4..cefacf928b33 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -398,6 +398,29 @@ static inline struct irq_2_iommu *irq_data_get_iommu(struct irq_data *d) | |||
398 | } | 398 | } |
399 | #endif | 399 | #endif |
400 | 400 | ||
401 | int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node); | ||
402 | void irq_free_descs(unsigned int irq, unsigned int cnt); | ||
403 | |||
404 | static inline int irq_alloc_desc(int node) | ||
405 | { | ||
406 | return irq_alloc_descs(-1, 0, 1, node); | ||
407 | } | ||
408 | |||
409 | static inline int irq_alloc_desc_at(unsigned int at, int node) | ||
410 | { | ||
411 | return irq_alloc_descs(at, at, 1, node); | ||
412 | } | ||
413 | |||
414 | static inline int irq_alloc_desc_from(unsigned int from, int node) | ||
415 | { | ||
416 | return irq_alloc_descs(-1, from, 1, node); | ||
417 | } | ||
418 | |||
419 | static inline void irq_free_desc(unsigned int irq) | ||
420 | { | ||
421 | irq_free_descs(irq, 1); | ||
422 | } | ||
423 | |||
401 | #endif /* CONFIG_GENERIC_HARDIRQS */ | 424 | #endif /* CONFIG_GENERIC_HARDIRQS */ |
402 | 425 | ||
403 | #endif /* !CONFIG_S390 */ | 426 | #endif /* !CONFIG_S390 */ |