--- linux-2.5/kernel/irq/manage.c 2004-10-29 16:39:08.496715752 +0300 +++ linuxppc_2.5-public/kernel/irq/manage.c 2004-10-29 16:44:13.361369280 +0300 @@ -10,6 +10,7 @@ #include #include #include +#include #include "internals.h" @@ -144,6 +145,53 @@ return !action; } +/* we must support request_irqs before mem init */ + +#define IRQ_CACHE_ENTRIES 8 /* 8 should be enough */ + +static spinlock_t irqa_lock = SPIN_LOCK_UNLOCKED; +static unsigned int irqa_cache_map = (1 << IRQ_CACHE_ENTRIES) - 1; +static struct irqaction irqa_cache[IRQ_CACHE_ENTRIES]; + +static struct irqaction *irqaction_alloc(int pri) +{ + extern int mem_init_done; + int i; + unsigned long flags; + struct irqaction *irqa; + + if (mem_init_done) + return kmalloc(sizeof(struct irqaction), pri); + + spin_lock_irqsave(&irqa_lock, flags); + i = ffs(irqa_cache_map); + if (i > 0 && --i < IRQ_CACHE_ENTRIES) { + irqa_cache_map &= ~(1 << i); + irqa = irqa_cache + i; + } else + irqa = NULL; + spin_unlock_irqrestore(&irqa_lock, flags); + + return irqa; +} + +static void irqaction_free(void *ptr) +{ + struct irqaction *irqa = ptr; + unsigned long flags; + int i; + + if (irqa < irqa_cache || irqa >= irqa_cache + IRQ_CACHE_ENTRIES) { + kfree(ptr); + return; + } + + spin_lock_irqsave(&irqa_lock, flags); + i = irqa_cache - irqa; + irqa_cache_map |= 1 << i; + spin_unlock_irqrestore(&irqa_lock, flags); +} + /* * Internal function to register an irqaction - typically used to * allocate special interrupts that are part of the architecture. @@ -265,7 +313,7 @@ /* Make sure it's not being used on another CPU */ synchronize_irq(irq); - kfree(action); + irqaction_free(action); return; } printk(KERN_ERR "Trying to free free IRQ%d\n",irq); @@ -325,7 +373,7 @@ if (!handler) return -EINVAL; - action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + action = irqaction_alloc(GFP_ATOMIC); if (!action) return -ENOMEM; @@ -337,10 +385,12 @@ action->dev_id = dev_id; retval = setup_irq(irq, action); - if (retval) - kfree(action); + if (retval) { + irqaction_free(action); + return retval; + } - return retval; + return 0; } EXPORT_SYMBOL(request_irq);