[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>
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 4c60a6e..aac8af5 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -154,9 +154,11 @@
 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 @@
 	}
 	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 @@
 #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 @@
 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 @@
 
 	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 @@
 		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 @@
 		       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 @@
 
 	kfree(action);
 
-	if (!(*(cpu_irq + irq_action)))
+	if (!sparc_irq[cpu_irq].action)
 		disable_irq(irq);
 
 out_unlock:
@@ -287,8 +287,11 @@
 #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 @@
 	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 @@
 	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 @@
 		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 @@
 
 	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 @@
 	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 @@
 		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 @@
 	    
 	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 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	if (tmp)
-		tmp->next = action;
-	else
-		*(cpu_irq + irq_action) = action;
+	*actionp = action;
 
 	enable_irq(irq);