[PATCH] ppc64: Detect altivec via firmware on unknown CPUs
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Sat, 16 Apr 2005 22:24:36 +0000 (15:24 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sat, 16 Apr 2005 22:24:36 +0000 (15:24 -0700)
This patch adds detection of the Altivec capability of the CPU via the
firmware in addition to the cpu table.  This allows newer CPUs that aren't
in the table to still have working altivec support in the kernel.

It also fixes a problem where if a CPU isn't recognized as having altivec
features, and takes an altivec unavailable exception due to userland
issuing altivec instructions, the kernel would happily enable it and
context switch the registers ...  but not all of them (it would basically
forget vrsave).  With this patch, the kernel will refuse to enable altivec
when the feature isn't detected for the CPU (SIGILL).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/ppc64/kernel/head.S
arch/ppc64/kernel/prom.c
arch/ppc64/kernel/traps.c

index fe05f3fbf9d059c623c3dc3fb02d9fd18f27b4ca..92a744c31ab183b2aec6e4532a593cef614bba13 100644 (file)
@@ -922,7 +922,9 @@ fp_unavailable_common:
 altivec_unavailable_common:
        EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
 #ifdef CONFIG_ALTIVEC
+BEGIN_FTR_SECTION
        bne     .load_up_altivec        /* if from user, just load it up */
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        bl      .save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
index 01739d5c47c7c0d9897ed04fd8597a80714a0fcd..b08aac68baff4a3c2b59f3337ea4b98cf60b64a3 100644 (file)
@@ -885,6 +885,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
                                          const char *full_path, void *data)
 {
        char *type = get_flat_dt_prop(node, "device_type", NULL);
+       u32 *prop;
 
        /* We are scanning "cpu" nodes only */
        if (type == NULL || strcmp(type, "cpu") != 0)
@@ -916,6 +917,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
                }
        }
 
+       /* Check if we have a VMX and eventually update CPU features */
+       prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL);
+       if (prop && (*prop) > 0) {
+               cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
+               cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+       }
+
+       /* Same goes for Apple's "altivec" property */
+       prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL);
+       if (prop) {
+               cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
+               cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+       }
+
        return 0;
 }
 
@@ -1104,7 +1119,9 @@ void __init early_init_devtree(void *params)
 
        DBG("Scanning CPUs ...\n");
 
-       /* Retreive hash table size from flattened tree */
+       /* Retreive hash table size from flattened tree plus other
+        * CPU related informations (altivec support, boot CPU ID, ...)
+        */
        scan_flat_dt(early_init_dt_scan_cpus, NULL);
 
        /* If hash size wasn't obtained above, we calculate it now based on
index 10fc61f3f6a430efbad91835eedcb787bad9a6bf..7e52cb2605e02bbf96be3a07e0b2872d8ce12e15 100644 (file)
@@ -450,14 +450,12 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs)
 
 void altivec_unavailable_exception(struct pt_regs *regs)
 {
-#ifndef CONFIG_ALTIVEC
        if (user_mode(regs)) {
                /* A user program has executed an altivec instruction,
                   but this kernel doesn't support altivec. */
                _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
                return;
        }
-#endif
        printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
                          "%lx at %lx\n", regs->trap, regs->nip);
        die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);