X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc64%2Fkernel%2Firq.c;h=2f777d55f3fb7d31e565359a9de43f1f8fbaf152;hb=08559aee03be26f1300e0b97f98cf5975095ec7a;hp=8461687468643a0f1fcd27b309c99f3a6443a11f;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 846168746..2f777d55f 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -143,6 +143,47 @@ EXPORT_SYMBOL(synchronize_irq); #endif /* CONFIG_SMP */ +/* XXX Make this into free_irq() - Anton */ + +/* This could be promoted to a real free_irq() ... */ +static int +do_free_irq(int irq, void* dev_id) +{ + irq_desc_t *desc = get_irq_desc(irq); + struct irqaction **p; + unsigned long flags; + + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + mask_irq(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + synchronize_irq(irq); + kfree(action); + return 0; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + break; + } + return -ENOENT; +} + + int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -153,7 +194,8 @@ int request_irq(unsigned int irq, if (irq >= NR_IRQS) return -EINVAL; if (!handler) - return -EINVAL; + /* We could implement really free_irq() instead of that... */ + return do_free_irq(irq, dev_id); action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -180,38 +222,7 @@ EXPORT_SYMBOL(request_irq); void free_irq(unsigned int irq, void *dev_id) { - irq_desc_t *desc = get_irq_desc(irq); - struct irqaction **p; - unsigned long flags; - - spin_lock_irqsave(&desc->lock,flags); - p = &desc->action; - for (;;) { - struct irqaction * action = *p; - if (action) { - struct irqaction **pp = p; - p = &action->next; - if (action->dev_id != dev_id) - continue; - - /* Found it - now remove it from the list of entries */ - *pp = action->next; - if (!desc->action) { - desc->status |= IRQ_DISABLED; - mask_irq(irq); - } - spin_unlock_irqrestore(&desc->lock,flags); - - /* Wait to make sure it's not being used on another CPU */ - synchronize_irq(irq); - kfree(action); - return; - } - printk("Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&desc->lock,flags); - break; - } - return; + request_irq(irq, NULL, 0, NULL, dev_id); } EXPORT_SYMBOL(free_irq); @@ -578,7 +589,7 @@ out: } #ifdef CONFIG_PPC_ISERIES -void do_IRQ(struct pt_regs *regs) +int do_IRQ(struct pt_regs *regs) { struct paca_struct *lpaca; struct ItLpQueue *lpq; @@ -618,13 +629,15 @@ void do_IRQ(struct pt_regs *regs) /* Signal a fake decrementer interrupt */ timer_interrupt(regs); } + + return 1; /* lets ret_from_int know we can do checks */ } #else /* CONFIG_PPC_ISERIES */ -void do_IRQ(struct pt_regs *regs) +int do_IRQ(struct pt_regs *regs) { - int irq; + int irq, first = 1; irq_enter(); @@ -643,15 +656,25 @@ void do_IRQ(struct pt_regs *regs) } #endif - irq = ppc_md.get_irq(regs); - - if (irq >= 0) + /* + * Every arch is required to implement ppc_md.get_irq. + * This function will either return an irq number or -1 to + * indicate there are no more pending. But the first time + * through the loop this means there wasn't an IRQ pending. + * The value -2 is for buggy hardware and means that this IRQ + * has already been handled. -- Tom + */ + while ((irq = ppc_md.get_irq(regs)) >= 0) { ppc_irq_dispatch_handler(regs, irq); - else + first = 0; + } + if (irq != -2 && first) /* That's not SMP safe ... but who cares ? */ ppc_spurious_interrupts++; irq_exit(); + + return 1; /* lets ret_from_int know we can do checks */ } #endif /* CONFIG_PPC_ISERIES */