summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/irq.c
diff options
context:
space:
mode:
authorBob Breuer <breuerr@mc.net>2006-03-23 22:36:19 -0800
committerDavid S. Miller <davem@davemloft.net>2006-03-23 22:36:19 -0800
commita54123e27779049d27d21e6c8adfee73aa2c0734 (patch)
tree265849e706e4ebe3b75127ebe6e3cbfe2a78850a /arch/sparc/kernel/irq.c
parent674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff)
[SPARC]: Try to start getting SMP back into shape.
Todo items: - IRQ_INPROGRESS flag - use sparc64 irq buckets, or generic irq_desc? - sun4d - re-indent large chunks of sun4m_smp.c - some places assume sequential cpu numbering (i.e. 0,1 instead of 0,2) Last I checked (with 2.6.14), random programs segfault with dual HyperSPARC. And with SuperSPARC II's, it seems stable but will eventually die from a write lock error (wrong lock owner or something). I haven't tried the HyperSPARC + highmem combination recently, so that may still be a problem. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/irq.c')
-rw-r--r--arch/sparc/kernel/irq.c66
1 files changed, 34 insertions, 32 deletions
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 4c60a6ef54a9..aac8af5aae51 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -154,9 +154,11 @@ void (*sparc_init_timers)(irqreturn_t (*)(int, void *,struct pt_regs *)) =
struct irqaction static_irqaction[MAX_STATIC_ALLOC];
int static_irq_count;
-struct irqaction *irq_action[NR_IRQS] = {
- [0 ... (NR_IRQS-1)] = NULL
-};
+struct {
+ struct irqaction *action;
+ int flags;
+} sparc_irq[NR_IRQS];
+#define SPARC_IRQ_INPROGRESS 1
/* Used to protect the IRQ action lists */
DEFINE_SPINLOCK(irq_action_lock);
@@ -177,7 +179,7 @@ int show_interrupts(struct seq_file *p, void *v)
}
spin_lock_irqsave(&irq_action_lock, flags);
if (i < NR_IRQS) {
- action = *(i + irq_action);
+ action = sparc_irq[i].action;
if (!action)
goto out_unlock;
seq_printf(p, "%3d: ", i);
@@ -186,7 +188,7 @@ int show_interrupts(struct seq_file *p, void *v)
#else
for_each_online_cpu(j) {
seq_printf(p, "%10u ",
- kstat_cpu(cpu_logical_map(j)).irqs[i]);
+ kstat_cpu(j).irqs[i]);
}
#endif
seq_printf(p, " %c %s",
@@ -207,7 +209,7 @@ out_unlock:
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action;
- struct irqaction * tmp = NULL;
+ struct irqaction **actionp;
unsigned long flags;
unsigned int cpu_irq;
@@ -225,7 +227,8 @@ void free_irq(unsigned int irq, void *dev_id)
spin_lock_irqsave(&irq_action_lock, flags);
- action = *(cpu_irq + irq_action);
+ actionp = &sparc_irq[cpu_irq].action;
+ action = *actionp;
if (!action->handler) {
printk("Trying to free free IRQ%d\n",irq);
@@ -235,7 +238,7 @@ void free_irq(unsigned int irq, void *dev_id)
for (; action; action = action->next) {
if (action->dev_id == dev_id)
break;
- tmp = action;
+ actionp = &action->next;
}
if (!action) {
printk("Trying to free free shared IRQ%d\n",irq);
@@ -254,11 +257,8 @@ void free_irq(unsigned int irq, void *dev_id)
irq, action->name);
goto out_unlock;
}
-
- if (action && tmp)
- tmp->next = action->next;
- else
- *(cpu_irq + irq_action) = action->next;
+
+ *actionp = action->next;
spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -268,7 +268,7 @@ void free_irq(unsigned int irq, void *dev_id)
kfree(action);
- if (!(*(cpu_irq + irq_action)))
+ if (!sparc_irq[cpu_irq].action)
disable_irq(irq);
out_unlock:
@@ -287,8 +287,11 @@ EXPORT_SYMBOL(free_irq);
#ifdef CONFIG_SMP
void synchronize_irq(unsigned int irq)
{
- printk("synchronize_irq says: implement me!\n");
- BUG();
+ unsigned int cpu_irq;
+
+ cpu_irq = irq & (NR_IRQS - 1);
+ while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS)
+ cpu_relax();
}
#endif /* SMP */
@@ -299,7 +302,7 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
unsigned int cpu_irq;
cpu_irq = irq & (NR_IRQS - 1);
- action = *(cpu_irq + irq_action);
+ action = sparc_irq[cpu_irq].action;
printk("IO device interrupt, irq = %d\n", irq);
printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc,
@@ -330,7 +333,8 @@ void handler_irq(int irq, struct pt_regs * regs)
if(irq < 10)
smp4m_irq_rotate(cpu);
#endif
- action = *(irq + irq_action);
+ action = sparc_irq[irq].action;
+ sparc_irq[irq].flags |= SPARC_IRQ_INPROGRESS;
kstat_cpu(cpu).irqs[irq]++;
do {
if (!action || !action->handler)
@@ -338,6 +342,7 @@ void handler_irq(int irq, struct pt_regs * regs)
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
+ sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS;
enable_pil_irq(irq);
irq_exit();
}
@@ -389,7 +394,7 @@ int request_fast_irq(unsigned int irq,
spin_lock_irqsave(&irq_action_lock, flags);
- action = *(cpu_irq + irq_action);
+ action = sparc_irq[cpu_irq].action;
if(action) {
if(action->flags & SA_SHIRQ)
panic("Trying to register fast irq when already shared.\n");
@@ -452,7 +457,7 @@ int request_fast_irq(unsigned int irq,
action->dev_id = NULL;
action->next = NULL;
- *(cpu_irq + irq_action) = action;
+ sparc_irq[cpu_irq].action = action;
enable_irq(irq);
@@ -467,7 +472,7 @@ int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char * devname, void *dev_id)
{
- struct irqaction * action, *tmp = NULL;
+ struct irqaction * action, **actionp;
unsigned long flags;
unsigned int cpu_irq;
int ret;
@@ -490,20 +495,20 @@ int request_irq(unsigned int irq,
spin_lock_irqsave(&irq_action_lock, flags);
- action = *(cpu_irq + irq_action);
+ actionp = &sparc_irq[cpu_irq].action;
+ action = *actionp;
if (action) {
- if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
- for (tmp = action; tmp->next; tmp = tmp->next);
- } else {
+ if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) {
ret = -EBUSY;
goto out_unlock;
}
- if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+ if ((action->flags & SA_INTERRUPT) != (irqflags & SA_INTERRUPT)) {
printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
ret = -EBUSY;
goto out_unlock;
- }
- action = NULL; /* Or else! */
+ }
+ for ( ; action; action = *actionp)
+ actionp = &action->next;
}
/* If this is flagged as statically allocated then we use our
@@ -532,10 +537,7 @@ int request_irq(unsigned int irq,
action->next = NULL;
action->dev_id = dev_id;
- if (tmp)
- tmp->next = action;
- else
- *(cpu_irq + irq_action) = action;
+ *actionp = action;
enable_irq(irq);