OpenPic etc changes for SMP Power3

Tom Gall tgall at rochcivictheatre.org
Sat Jan 13 16:20:01 EST 2001


Hi All,

  Enclosed is a candidate patch for the current 2.4 tree. The set of
changes include:

1) The removal of openpic_setup_ISU (code moved to rewritten find_ISUs)
2) addition of a few IPI specific functions in open_pic.c
    The reason is mostly centered on POWER3 has a *cough* feature that
you write be but read le when it comes to IPIs.
3) openpic_mapirq only should allow IRQs to go to processor one. The
software interrupt handler is not SMP safe.
4) openpic_enable_irq and openpic_disable_irq should no longer allow the

enablement or disablement of a timer or IPI irq
5) fixed a couple of bugs in smp.c when openpic_cause_IPI was called
with the param computed incorrectly

Additionally some changes (that I will push) for arch/ppc/mm/init.c
are included.
These used to be in the sources and I believe were lost as a result of
the recent difficulties with bk. Regardless they are included.

 Please try and send comments back to tgall at rochcivictheatre.org /
tom_gall at vnet.ibm.com

  I am especially concerned that I don't break anybody else by these
changes or regress current function in 2.4.

  While I have tried to test as much as possible, I ran out of time
today and didn't get a chance to test boot on a b50 (604 chrp) and a F50

(4 way 604 chrp) but I did try this kernel out on a 170 (uni Power3) and

270 ( 2 way Power3) with success.

  Thanks!

--
Hakuna Matata,

Tom

-----------------------------------------------------------
PPC Linux Guy      "My heart is human, my blood is boiling,
                    my brain IBM" -- Mr Roboto, Styxx
tgall at rochcivictheatre.org


-------------- next part --------------
diff -ur linuxppc_2_4/arch/ppc/kernel/chrp_pci.c linuxppc_2_4.works/arch/ppc/kernel/chrp_pci.c
--- linuxppc_2_4/arch/ppc/kernel/chrp_pci.c	Thu Jan 11 17:22:14 2001
+++ linuxppc_2_4.works/arch/ppc/kernel/chrp_pci.c	Fri Jan 12 16:13:55 2001
@@ -403,10 +403,6 @@

 		process_bridge_ranges(hose, dev, index);

-#ifdef CONFIG_POWER3
-                openpic_setup_ISU(index, opprop[index+1]);
-#endif /* CONFIG_POWER3 */
-
 		/* check the first bridge for a property that we can
 		   use to set pci_dram_offset */
 		dma = (unsigned int *)
diff -ur linuxppc_2_4/arch/ppc/kernel/irq.c linuxppc_2_4.works/arch/ppc/kernel/irq.c
--- linuxppc_2_4/arch/ppc/kernel/irq.c	Thu Jan 11 17:22:24 2001
+++ linuxppc_2_4.works/arch/ppc/kernel/irq.c	Fri Jan 12 16:12:06 2001
@@ -172,6 +172,7 @@
 	}
 	spin_unlock_irqrestore(&desc->lock,flags);

+
 	register_irq_proc(irq);
 	return 0;
 }
diff -ur linuxppc_2_4/arch/ppc/kernel/open_pic.c linuxppc_2_4.works/arch/ppc/kernel/open_pic.c
--- linuxppc_2_4/arch/ppc/kernel/open_pic.c	Thu Jan 11 17:22:26 2001
+++ linuxppc_2_4.works/arch/ppc/kernel/open_pic.c	Fri Jan 12 16:16:09 2001
@@ -136,6 +136,19 @@
 	return val;
 }

+/* yes this is right ... bug, feature, you decide! -- tgall */
+u_int openpic_read_IPI(volatile u_int* addr)
+{
+         u_int val = 0;
+#ifdef CONFIG_POWER3
+        val = in_be32(addr);
+#else
+        val = in_le32(addr);
+#endif
+        return val;
+}
+
+
 static inline void openpic_write(volatile u_int *addr, u_int val)
 {
 	out_le32(addr, val);
@@ -154,16 +167,33 @@
 	openpic_write(addr, (val & ~mask) | (field & mask));
 }

+/* because of the power3 be / le above, this is needed */
+inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
+{
+        u_int  val = openpic_read_IPI(addr);
+        openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
 {
 	openpic_writefield(addr, mask, 0);
 }

+static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
+{
+        openpic_writefield_IPI(addr, mask, 0);
+}
+
 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
 {
 	openpic_writefield(addr, mask, mask);
 }

+static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
+{
+        openpic_writefield_IPI(addr, mask, mask);
+}
+
 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
 				    u_int field)
 {
@@ -172,6 +202,19 @@
 	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
 }

+static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
+{
+        openpic_setfield_IPI(addr, OPENPIC_MASK);
+
+        /* wait until it's not in use */
+        /* BenH: Is this code really enough ? I would rather check the result
+         *       and eventually retry ...
+         */
+        while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
+
+        openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
 			 int programmer_switch_irq)
 {
@@ -291,37 +334,47 @@
 	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
 }

-#ifdef CONFIG_POWER3
-void openpic_setup_ISU(int isu_num, unsigned long addr)
-{
-	if (isu_num >= OPENPIC_MAX_ISU)
-		return;
-	ISU[isu_num] = (OpenPIC_SourcePtr) ioremap(addr, 0x400);
-	if (isu_num >= NumISUs)
-		NumISUs = isu_num + 1;
-}
-#endif
-
 void find_ISUs(void)
 {
-#ifdef CONFIG_POWER3
-        /* Use /interrupt-controller/reg and
-         * /interrupt-controller/interrupt-ranges from OF device tree
-	 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
-	 * as a result
-	 * -- tgall
+        unsigned long *opprop;
+        int len, i;
+
+        opprop = (unsigned long *)get_property(find_path_device("/"),
+                 "platform-open-pic", &len);
+
+        if (!opprop) {
+                 printk("find_ISUs(): could not read platform-open-pic");
+                return;
+        }
+
+        if (!opprop[1]) {
+                /*
+                 * for non-distributed OpenPIC
+                 * implementations it's in the IDU -- Cort
+                 */
+                ISU[0] = (OpenPIC_Source *)OpenPIC->Source;
+                return;
+        }
+        NumSources = 0;
+        len /= sizeof(unsigned int);
+
+        /* basically each ISU is a bus, and this assumes that
+         * open_pic_isu_count interrupts per bus are possible
+         * ISU == Interrupt Source Unit
          */

-	/* basically each ISU is a bus, and this assumes that
-	 * open_pic_isu_count interrupts per bus are possible
-	 * ISU == Interrupt Source
-	 */
-	NumSources = NumISUs * 0x10;
+        /* I hope there is no case where the first OpenPIC address does
+         * not correspond to the first Bus.  - tibit
+         */

-#else
-	/* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
-	ISU[0] = (OpenPIC_Source *)OpenPIC->Source;
-#endif
+        for (i = 0; i < len-1; i++) {
+                ISU[i] = (OpenPIC_Source *) ioremap (opprop[i+1], 0x20);
+                printk("Setting up ISU(%d) at 0x%lx, remapped to 0x%p\n",
+                        i, opprop[i+1], ISU[i]);
+                NumSources += 0x10;
+        }
+	NumISUs=(NumSources / 0x10) + 1;
+printk("This OpenPIC can handle %d Interrupt Sources\n", NumSources);
 }

 static void openpic_reset(void)
@@ -438,7 +491,7 @@
 	check_arg_ipi(ipi);
 	check_arg_pri(pri);
 	check_arg_vec(vec);
-	openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+	openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
 				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
 				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
 }
@@ -502,9 +555,10 @@
  	/* let the openpic know we want intrs. default affinity
  	 * is 0xffffffff until changed via /proc
  	 */
+#if 0
  	for (i = 0; i < NumSources ; i++)
 		openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
-
+#endif
  	openpic_set_priority(0);

 	spin_unlock(&openpic_setup_lock);
@@ -554,6 +608,21 @@
 static void openpic_enable_irq(u_int irq)
 {
 	check_arg_irq(irq);
+
+        /*
+         * Never want to disable a timer or ipi irq
+         * (only want to disable irqs within an ISU).
+         */
+        if (((irq >= OPENPIC_VEC_IPI+open_pic_irq_offset)   &&
+           (irq <  OPENPIC_VEC_IPI+open_pic_irq_offset+OPENPIC_NUM_IPI)) ||
+           ((irq >= OPENPIC_VEC_TIMER+open_pic_irq_offset) &&
+            (irq <  OPENPIC_VEC_TIMER+open_pic_irq_offset+OPENPIC_NUM_TIMERS)))
+        {
+        /* silently ignore the enable of the timer or ipi irq. */
+        return;
+        }
+
+
 	openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
@@ -567,6 +636,19 @@
 	u32 vp;

 	check_arg_irq(irq);
+        /*
+         * Never want to disable a timer or ipi irq
+         * (only want to disable irqs within an ISU).
+         */
+        if (((irq >= OPENPIC_VEC_IPI+open_pic_irq_offset)   &&
+             (irq <  OPENPIC_VEC_IPI+open_pic_irq_offset+OPENPIC_NUM_IPI)) ||
+             ((irq >= OPENPIC_VEC_TIMER+open_pic_irq_offset) &&
+             (irq <  OPENPIC_VEC_TIMER+open_pic_irq_offset+OPENPIC_NUM_TIMERS)))
+        {
+                panic("openpic_disable_irq - disabling non-ISU irq");
+        }
+
+
 	openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
@@ -586,27 +668,14 @@
 {
 	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
 	check_arg_ipi(irq);
-	openpic_clearfield(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
-	/* make sure mask gets to controller before we return to user */
-	do {
-		mb(); /* sync is probably useless here */
-	} while(openpic_readfield(&OpenPIC->Global.IPI_Vector_Priority(irq),
-				  OPENPIC_MASK));
+	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
+
 }
 void openpic_disable_ipi(u_int irq)
 {
-	u32 vp;
-
-	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
-	check_arg_ipi(irq);
-	openpic_setfield(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
-	/* make sure mask gets to controller before we return to user */
-	do {
-		mb();  /* sync is probably useless here */
-		vp = openpic_readfield(&OpenPIC->Global.IPI_Vector_Priority(irq),
-    			OPENPIC_MASK | OPENPIC_ACTIVITY);
-	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
+   /* NEVER disable an IPI... that's just plain wrong! */
 }
+
 #endif

 /*
diff -ur linuxppc_2_4/arch/ppc/kernel/smp.c linuxppc_2_4.works/arch/ppc/kernel/smp.c
--- linuxppc_2_4/arch/ppc/kernel/smp.c	Thu Jan 11 17:22:17 2001
+++ linuxppc_2_4.works/arch/ppc/kernel/smp.c	Fri Jan 12 16:17:55 2001
@@ -424,10 +424,11 @@
 		break;
 	case MSG_ALL_BUT_SELF:
 		openpic_cause_IPI(msg,
-				  0xffffffff & ~(1 << smp_processor_id()));
+       			0xffffffff & ~(1 << smp_hw_index[smp_processor_id()]));
+
 		break;
 	default:
-		openpic_cause_IPI(msg, 1<<target);
+		openpic_cause_IPI(msg, smp_hw_index[1<<target]);
 		break;
 	}
 }
diff -ur linuxppc_2_4/arch/ppc/mm/init.c linuxppc_2_4.works/arch/ppc/mm/init.c
--- linuxppc_2_4/arch/ppc/mm/init.c	Thu Jan 11 17:22:15 2001
+++ linuxppc_2_4.works/arch/ppc/mm/init.c	Fri Jan 12 16:02:04 2001
@@ -74,6 +74,7 @@

 int prom_trashed;
 atomic_t next_mmu_context;
+rwlock_t context_overflow_lock __cacheline_aligned = RW_LOCK_UNLOCKED;
 unsigned long *end_of_DRAM;
 unsigned long total_memory;
 unsigned long total_lowmem;
@@ -633,24 +634,32 @@
 	struct task_struct *tsk;

 	printk(KERN_DEBUG "mmu_context_overflow\n");
-	read_lock(&tasklist_lock);
- 	for_each_task(tsk) {
-		if (tsk->mm)
-			tsk->mm->context = NO_CONTEXT;
-	}
-	read_unlock(&tasklist_lock);
-	flush_hash_segments(0x10, 0xffffff);
+	/* acquire the write lock for context overflow */
+	write_lock (&context_overflow_lock);
+	/* recheck if overflow still exists */
+	if (atomic_read(&next_mmu_context) == LAST_CONTEXT) {
+		read_lock(&tasklist_lock);
+		for_each_task(tsk) {
+			if (tsk->mm)
+				tsk->mm->context = NO_CONTEXT;
+
+		}
+		read_unlock(&tasklist_lock);
+		flush_hash_segments(0x10, 0xffffff);
 #ifdef CONFIG_SMP
-	smp_send_tlb_invalidate(0);
+		smp_send_tlb_invalidate(0);
 #endif
-	atomic_set(&next_mmu_context, 0);
-	/* make sure current always has a context */
-	current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context));
-	/* The PGD is only a placeholder.  It is only used on
-	 * 8xx processors.
-	 */
-	set_context(current->mm->context, current->mm->pgd);
-}
+		atomic_set(&next_mmu_context, 0);
+	}
+	write_unlock (&context_overflow_lock);
+	/* make sure current always has a context */
+	/* need to check to assure current task has an mm */
+	/*   - idle thread does not have an MM */
+	if (current->mm) {
+		current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context));
+		set_context(current->mm->context, current->mm->pgd);
+	}
+}
 #else /* CONFIG_8xx */
 void
 mmu_context_overflow(void)
@@ -1058,8 +1067,10 @@
 		 * down and slap your hands.  If it causes problems please email me.
 		 *  -- Cort <cort at fsmlabs.com>
 		 */
+#ifndef CONFIG_POWER3
 		setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
 		setbat(1, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
+#endif
 		break;
 	case _MACH_Pmac:
 		ioremap_base = 0xfe000000;


More information about the Linuxppc-dev mailing list