From: Krzysztof Helt <[EMAIL PROTECTED]>

This patch changes call definitions of the restore_current(void)
to restore_current(int) to force usage of the o0 register. The o0
register is used internally and compiler must not assume
it is preserved during the call.

Signed-off-by: Krzysztof Helt <[EMAIL PROTECTED]>

---

Dave, if it is not a real issue please discard the patch.

I did the patch against the 2.6.23-rc3-git6 kernel. 
It does not help with crashes inside prom functions
I observe on the SMP kernel.

Longer explanation.

The "void restore_current(void)" definition does not
give any hint to the compiler that o0 register will be
trashed inside the call. See the following sequence:

    spin_lock_irqsave(&prom_lock, flags);
    if(prom_vers != PROM_V0)
        (*(romvec->pv_fortheval.v2_eval))(fstring);
    else
        ret = -1;
    restore_current();
    spin_unlock_irqrestore(&prom_lock, flags);

If the prom_vers is PROM_V0 the compiler
may assume that prom_lock address is still
in the o0 register which is not because the
restore_current() has overwritten it.

The added parameter forces the gcc to
load value into the o0 register before the
restore_current() call thus force reloading it
before the next call.

It does not matter in a simpler case:

    spin_lock_irqsave(&prom_lock, flags);
    (*(romvec->prom_call))(args);
    restore_current();
    spin_unlock_irqrestore(&prom_lock, flags);

because the o0 was used by the prom_call so it has to
be reloaded before the spin_unlock and no side effect
happens.

I don't know if it has something to do with the crash
in the atomic_add_unless() which I observe sometimes
on SMP kernel (SS20) around the floppy driver load
(just before or just after the text about FDC driver).
I can confirm it after few days of testing because it
happens randomly.

diff -urp linux-2.6.23/arch/sparc/kernel/prom.c 
linux-sparc/arch/sparc/kernel/prom.c
--- linux-2.6.23/arch/sparc/kernel/prom.c       2007-08-26 07:23:41.120488968 
+0200
+++ linux-sparc/arch/sparc/kernel/prom.c        2007-08-26 18:36:48.122933751 
+0200
@@ -421,7 +421,7 @@ EXPORT_SYMBOL(of_console_path);
 char *of_console_options;
 EXPORT_SYMBOL(of_console_options);
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 static void __init of_console_init(void)
 {
@@ -482,7 +482,7 @@ static void __init of_console_init(void)
 
                spin_lock_irqsave(&prom_lock, flags);
                node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
-               restore_current();
+               restore_current(0);
                spin_unlock_irqrestore(&prom_lock, flags);
 
                if (!node) {
diff -urp linux-2.6.23/arch/sparc/prom/console.c 
linux-sparc/arch/sparc/prom/console.c
--- linux-2.6.23/arch/sparc/prom/console.c      2007-08-26 07:23:41.232495351 
+0200
+++ linux-sparc/arch/sparc/prom/console.c       2007-08-26 18:39:02.486590699 
+0200
@@ -15,7 +15,7 @@
 #include <asm/system.h>
 #include <linux/string.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 static char con_name_jmc[] = "/obio/su@"; /* "/obio/[EMAIL PROTECTED],3002f8"; 
*/
 #define CON_SIZE_JMC   (sizeof(con_name_jmc))
@@ -48,7 +48,7 @@ prom_nbgetchar(void)
                i = -1;
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return i; /* Ugh, we could spin forever on unsupported proms ;( */
 }
@@ -81,7 +81,7 @@ prom_nbputchar(char c)
                i = -1;
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return i; /* Ugh, we could spin forever on unsupported proms ;( */
 }
diff -urp linux-2.6.23/arch/sparc/prom/devmap.c 
linux-sparc/arch/sparc/prom/devmap.c
--- linux-2.6.23/arch/sparc/prom/devmap.c       2007-07-09 01:32:17.000000000 
+0200
+++ linux-sparc/arch/sparc/prom/devmap.c        2007-08-26 18:37:14.780452876 
+0200
@@ -11,7 +11,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 /* Just like the routines in palloc.c, these should not be used
  * by the kernel at all.  Bootloader facility mainly.  And again,
@@ -34,7 +34,7 @@ prom_mapio(char *vhint, int ios, unsigne
        else
        ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
                                                    num_bytes);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return ret;
 }
@@ -48,7 +48,7 @@ prom_unmapio(char *vaddr, unsigned int n
        if(num_bytes == 0x0) return;
        spin_lock_irqsave(&prom_lock, flags);
        (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return;
 }
diff -urp linux-2.6.23/arch/sparc/prom/devops.c 
linux-sparc/arch/sparc/prom/devops.c
--- linux-2.6.23/arch/sparc/prom/devops.c       2007-07-09 01:32:17.000000000 
+0200
+++ linux-sparc/arch/sparc/prom/devops.c        2007-08-26 18:37:40.085894951 
+0200
@@ -10,7 +10,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 /* Open the device described by the string 'dstr'.  Returns the handle
  * to that device used for subsequent operations on that device.
@@ -35,7 +35,7 @@ prom_devopen(char *dstr)
                handle = -1;
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return handle;
@@ -58,7 +58,7 @@ prom_devclose(int dhandle)
        default:
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return 0;
 }
@@ -82,7 +82,7 @@ prom_seek(int dhandle, unsigned int seek
        default:
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return;
diff -urp linux-2.6.23/arch/sparc/prom/misc.c linux-sparc/arch/sparc/prom/misc.c
--- linux-2.6.23/arch/sparc/prom/misc.c 2007-08-26 07:23:41.236495579 +0200
+++ linux-sparc/arch/sparc/prom/misc.c  2007-08-26 18:39:19.123538785 +0200
@@ -13,7 +13,7 @@
 #include <asm/auxio.h>
 #include <asm/system.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 DEFINE_SPINLOCK(prom_lock);
 
@@ -25,7 +25,7 @@ prom_reboot(char *bcommand)
        spin_lock_irqsave(&prom_lock, flags);
        (*(romvec->pv_reboot))(bcommand);
        /* Never get here. */
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 }
 
@@ -41,7 +41,7 @@ prom_feval(char *fstring)
                (*(romvec->pv_fortheval.v0_eval))(strlen(fstring), fstring);
        else
                (*(romvec->pv_fortheval.v2_eval))(fstring);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 }
 
@@ -63,7 +63,7 @@ prom_cmdline(void)
        spin_lock_irqsave(&prom_lock, flags);
        install_obp_ticker();
        (*(romvec->pv_abort))();
-       restore_current();
+       restore_current(0);
        install_linux_ticker();
        spin_unlock_irqrestore(&prom_lock, flags);
 #ifdef CONFIG_SUN_AUXIO
@@ -84,7 +84,7 @@ again:
        spin_lock_irqsave(&prom_lock, flags);
        (*(romvec->pv_halt))();
        /* Never get here. */
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        goto again; /* PROM is out to get me -DaveM */
 }
diff -urp linux-2.6.23/arch/sparc/prom/mp.c linux-sparc/arch/sparc/prom/mp.c
--- linux-2.6.23/arch/sparc/prom/mp.c   2007-07-09 01:32:17.000000000 +0200
+++ linux-sparc/arch/sparc/prom/mp.c    2007-08-26 18:38:00.471056635 +0200
@@ -12,7 +12,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 /* Start cpu with prom-tree node 'cpunode' using context described
  * by 'ctable_reg' in context 'ctx' at program counter 'pc'.
@@ -36,7 +36,7 @@ prom_startcpu(int cpunode, struct linux_
                ret = (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, 
pc);
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return ret;
@@ -62,7 +62,7 @@ prom_stopcpu(int cpunode)
                ret = (*(romvec->v3_cpustop))(cpunode);
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return ret;
@@ -88,7 +88,7 @@ prom_idlecpu(int cpunode)
                ret = (*(romvec->v3_cpuidle))(cpunode);
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return ret;
@@ -114,7 +114,7 @@ prom_restartcpu(int cpunode)
                ret = (*(romvec->v3_cpuresume))(cpunode);
                break;
        };
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return ret;
diff -urp linux-2.6.23/arch/sparc/prom/segment.c 
linux-sparc/arch/sparc/prom/segment.c
--- linux-2.6.23/arch/sparc/prom/segment.c      2007-07-09 01:32:17.000000000 
+0200
+++ linux-sparc/arch/sparc/prom/segment.c       2007-08-26 18:38:23.052343469 
+0200
@@ -12,7 +12,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 /* Set physical segment 'segment' at virtual address 'vaddr' in
  * context 'ctx'.
@@ -23,7 +23,7 @@ prom_putsegment(int ctx, unsigned long v
        unsigned long flags;
        spin_lock_irqsave(&prom_lock, flags);
        (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return;
 }
diff -urp linux-2.6.23/arch/sparc/prom/tree.c linux-sparc/arch/sparc/prom/tree.c
--- linux-2.6.23/arch/sparc/prom/tree.c 2007-07-09 01:32:17.000000000 +0200
+++ linux-sparc/arch/sparc/prom/tree.c  2007-08-26 18:38:48.297782125 +0200
@@ -16,7 +16,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-extern void restore_current(void);
+extern void restore_current(int);
 
 static char promlib_buf[128];
 
@@ -28,7 +28,7 @@ int __prom_getchild(int node)
 
        spin_lock_irqsave(&prom_lock, flags);
        cnode = prom_nodeops->no_child(node);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return cnode;
@@ -59,7 +59,7 @@ int __prom_getsibling(int node)
 
        spin_lock_irqsave(&prom_lock, flags);
        cnode = prom_nodeops->no_nextnode(node);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return cnode;
@@ -95,7 +95,7 @@ int prom_getproplen(int node, char *prop
                
        spin_lock_irqsave(&prom_lock, flags);
        ret = prom_nodeops->no_proplen(node, prop);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return ret;
 }
@@ -115,7 +115,7 @@ int prom_getproperty(int node, char *pro
        /* Ok, things seem all right. */
        spin_lock_irqsave(&prom_lock, flags);
        ret = prom_nodeops->no_getprop(node, prop, buffer);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return ret;
 }
@@ -213,7 +213,7 @@ char * __prom_nextprop(int node, char * 
 
        spin_lock_irqsave(&prom_lock, flags);
        prop = prom_nodeops->no_nextprop(node, oprop);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
 
        return prop;
@@ -312,7 +312,7 @@ int prom_setprop(int node, char *pname, 
        if((pname == 0) || (value == 0)) return 0;
        spin_lock_irqsave(&prom_lock, flags);
        ret = prom_nodeops->no_setprop(node, pname, value, size);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        return ret;
 }
@@ -324,7 +324,7 @@ int prom_inst2pkg(int inst)
        
        spin_lock_irqsave(&prom_lock, flags);
        node = (*romvec->pv_v2devops.v2_inst2pkg)(inst);
-       restore_current();
+       restore_current(0);
        spin_unlock_irqrestore(&prom_lock, flags);
        if (node == -1) return 0;
        return node;
-
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to