aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-04-16 18:24:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:24:36 -0400
commit187335a4ec72c9bc7f3f168d6858a41fcfb63302 (patch)
treed5f1ae0d320e6325ed056469773e855fc635c53d /arch/ppc64
parent547ee84cea37696d25c93306e909378a87db2f66 (diff)
[PATCH] ppc64: Detect altivec via firmware on unknown CPUs
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>
Diffstat (limited to 'arch/ppc64')
-rw-r--r--arch/ppc64/kernel/head.S2
-rw-r--r--arch/ppc64/kernel/prom.c19
-rw-r--r--arch/ppc64/kernel/traps.c2
3 files changed, 20 insertions, 3 deletions
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index fe05f3fbf9d0..92a744c31ab1 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -922,7 +922,9 @@ fp_unavailable_common:
922altivec_unavailable_common: 922altivec_unavailable_common:
923 EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) 923 EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
924#ifdef CONFIG_ALTIVEC 924#ifdef CONFIG_ALTIVEC
925BEGIN_FTR_SECTION
925 bne .load_up_altivec /* if from user, just load it up */ 926 bne .load_up_altivec /* if from user, just load it up */
927END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
926#endif 928#endif
927 bl .save_nvgprs 929 bl .save_nvgprs
928 addi r3,r1,STACK_FRAME_OVERHEAD 930 addi r3,r1,STACK_FRAME_OVERHEAD
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 01739d5c47c7..b08aac68baff 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -885,6 +885,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
885 const char *full_path, void *data) 885 const char *full_path, void *data)
886{ 886{
887 char *type = get_flat_dt_prop(node, "device_type", NULL); 887 char *type = get_flat_dt_prop(node, "device_type", NULL);
888 u32 *prop;
888 889
889 /* We are scanning "cpu" nodes only */ 890 /* We are scanning "cpu" nodes only */
890 if (type == NULL || strcmp(type, "cpu") != 0) 891 if (type == NULL || strcmp(type, "cpu") != 0)
@@ -916,6 +917,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
916 } 917 }
917 } 918 }
918 919
920 /* Check if we have a VMX and eventually update CPU features */
921 prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL);
922 if (prop && (*prop) > 0) {
923 cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
924 cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
925 }
926
927 /* Same goes for Apple's "altivec" property */
928 prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL);
929 if (prop) {
930 cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
931 cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
932 }
933
919 return 0; 934 return 0;
920} 935}
921 936
@@ -1104,7 +1119,9 @@ void __init early_init_devtree(void *params)
1104 1119
1105 DBG("Scanning CPUs ...\n"); 1120 DBG("Scanning CPUs ...\n");
1106 1121
1107 /* Retreive hash table size from flattened tree */ 1122 /* Retreive hash table size from flattened tree plus other
1123 * CPU related informations (altivec support, boot CPU ID, ...)
1124 */
1108 scan_flat_dt(early_init_dt_scan_cpus, NULL); 1125 scan_flat_dt(early_init_dt_scan_cpus, NULL);
1109 1126
1110 /* If hash size wasn't obtained above, we calculate it now based on 1127 /* If hash size wasn't obtained above, we calculate it now based on
diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
index 10fc61f3f6a4..7e52cb2605e0 100644
--- a/arch/ppc64/kernel/traps.c
+++ b/arch/ppc64/kernel/traps.c
@@ -450,14 +450,12 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs)
450 450
451void altivec_unavailable_exception(struct pt_regs *regs) 451void altivec_unavailable_exception(struct pt_regs *regs)
452{ 452{
453#ifndef CONFIG_ALTIVEC
454 if (user_mode(regs)) { 453 if (user_mode(regs)) {
455 /* A user program has executed an altivec instruction, 454 /* A user program has executed an altivec instruction,
456 but this kernel doesn't support altivec. */ 455 but this kernel doesn't support altivec. */
457 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); 456 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
458 return; 457 return;
459 } 458 }
460#endif
461 printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " 459 printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
462 "%lx at %lx\n", regs->trap, regs->nip); 460 "%lx at %lx\n", regs->trap, regs->nip);
463 die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); 461 die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);