]> err.no Git - linux-2.6/commitdiff
[POWERPC] Rework SMP timebase handoff for pasemi
authorOlof Johansson <olof@lixom.net>
Wed, 22 Aug 2007 02:26:43 +0000 (12:26 +1000)
committerPaul Mackerras <paulus@samba.org>
Wed, 22 Aug 2007 05:37:11 +0000 (15:37 +1000)
Rework timebase handoff to play nice with configurations with more than
2 cores, as well as with CPU hotplug.

Previous scheme just pushed out the current timebase from the giving
core to all cores without caring if they wanted it or not, nor checking
if they'd taken it. The taking side didn't make sure the giving side
had provided a value yet either. In other words, it was completely broken.

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/pasemi/setup.c

index ffe6528048b57121a6b4e8d74ee509871b3aa24b..05def6282f830204f76a4d206fa5fa39909da3e6 100644 (file)
@@ -50,26 +50,30 @@ static void pas_restart(char *cmd)
 
 #ifdef CONFIG_SMP
 static DEFINE_SPINLOCK(timebase_lock);
+static unsigned long timebase;
 
 static void __devinit pas_give_timebase(void)
 {
-       unsigned long tb;
-
        spin_lock(&timebase_lock);
        mtspr(SPRN_TBCTL, TBCTL_FREEZE);
-       tb = mftb();
-       mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff));
-       mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32));
-       mtspr(SPRN_TBCTL, TBCTL_RESTART);
+       isync();
+       timebase = get_tb();
        spin_unlock(&timebase_lock);
-       pr_debug("pas_give_timebase: cpu %d gave tb %lx\n",
-                smp_processor_id(), tb);
+
+       while (timebase)
+               barrier();
+       mtspr(SPRN_TBCTL, TBCTL_RESTART);
 }
 
 static void __devinit pas_take_timebase(void)
 {
-       pr_debug("pas_take_timebase: cpu %d has tb %lx\n",
-                smp_processor_id(), mftb());
+       while (!timebase)
+               smp_rmb();
+
+       spin_lock(&timebase_lock);
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       spin_unlock(&timebase_lock);
 }
 
 struct smp_ops_t pas_smp_ops = {