[SPARC64]: Detect sun4v early in boot process.
[cascardo/linux.git] / arch / sparc64 / kernel / setup.c
index c1f3423..7f02c8f 100644 (file)
@@ -154,6 +154,7 @@ int prom_callback(long *args)
                        pud_t *pudp;
                        pmd_t *pmdp;
                        pte_t *ptep;
+                       pte_t pte;
 
                        for_each_process(p) {
                                mm = p->mm;
@@ -178,8 +179,9 @@ int prom_callback(long *args)
                         * being called from inside OBP.
                         */
                        ptep = pte_offset_map(pmdp, va);
-                       if (pte_present(*ptep)) {
-                               tte = pte_val(*ptep);
+                       pte = *ptep;
+                       if (pte_present(pte)) {
+                               tte = pte_val(pte);
                                res = PROM_TRUE;
                        }
                        pte_unmap(ptep);
@@ -187,26 +189,30 @@ int prom_callback(long *args)
                }
 
                if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
-                       extern unsigned long sparc64_kern_pri_context;
-
-                       /* Spitfire Errata #32 workaround */
-                       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
-                                            "flush     %%g6"
-                                            : /* No outputs */
-                                            : "r" (sparc64_kern_pri_context),
-                                              "r" (PRIMARY_CONTEXT),
-                                              "i" (ASI_DMMU));
+                       if (tlb_type == spitfire) {
+                               extern unsigned long sparc64_kern_pri_context;
+
+                               /* Spitfire Errata #32 workaround */
+                               __asm__ __volatile__(
+                                       "stxa   %0, [%1] %2\n\t"
+                                       "flush  %%g6"
+                                       : /* No outputs */
+                                       : "r" (sparc64_kern_pri_context),
+                                         "r" (PRIMARY_CONTEXT),
+                                         "i" (ASI_DMMU));
+                       }
 
                        /*
                         * Locked down tlb entry.
                         */
 
-                       if (tlb_type == spitfire)
+                       if (tlb_type == spitfire) {
                                tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
-                       else if (tlb_type == cheetah || tlb_type == cheetah_plus)
+                               res = PROM_TRUE;
+                       } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
                                tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
-
-                       res = PROM_TRUE;
+                               res = PROM_TRUE;
+                       }
                        goto done;
                }
 
@@ -218,6 +224,7 @@ int prom_callback(long *args)
                        pud_t *pudp;
                        pmd_t *pmdp;
                        pte_t *ptep;
+                       pte_t pte;
                        int error;
 
                        if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) {
@@ -240,8 +247,9 @@ int prom_callback(long *args)
                         * being called from inside OBP.
                         */
                        ptep = pte_offset_kernel(pmdp, va);
-                       if (pte_present(*ptep)) {
-                               tte = pte_val(*ptep);
+                       pte = *ptep;
+                       if (pte_present(pte)) {
+                               tte = pte_val(pte);
                                res = PROM_TRUE;
                        }
                        goto done;
@@ -486,6 +494,103 @@ void register_prom_callbacks(void)
                   "' linux-.soft2 to .soft2");
 }
 
+static void __init per_cpu_patch(void)
+{
+#ifdef CONFIG_SMP
+       struct cpuid_patch_entry *p;
+       unsigned long ver;
+       int is_jbus;
+
+       if (tlb_type == spitfire && !this_is_starfire)
+               return;
+
+       is_jbus = 0;
+       if (tlb_type != hypervisor) {
+               __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+               is_jbus = ((ver >> 32) == __JALAPENO_ID ||
+                          (ver >> 32) == __SERRANO_ID);
+       }
+
+       p = &__cpuid_patch;
+       while (p < &__cpuid_patch_end) {
+               unsigned long addr = p->addr;
+               unsigned int *insns;
+
+               switch (tlb_type) {
+               case spitfire:
+                       insns = &p->starfire[0];
+                       break;
+               case cheetah:
+               case cheetah_plus:
+                       if (is_jbus)
+                               insns = &p->cheetah_jbus[0];
+                       else
+                               insns = &p->cheetah_safari[0];
+                       break;
+               case hypervisor:
+                       insns = &p->sun4v[0];
+                       break;
+               default:
+                       prom_printf("Unknown cpu type, halting.\n");
+                       prom_halt();
+               };
+
+               *(unsigned int *) (addr +  0) = insns[0];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  0));
+
+               *(unsigned int *) (addr +  4) = insns[1];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  4));
+
+               *(unsigned int *) (addr +  8) = insns[2];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  8));
+
+               *(unsigned int *) (addr + 12) = insns[3];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr + 12));
+
+               p++;
+       }
+#endif
+}
+
+static void __init sun4v_patch(void)
+{
+       struct sun4v_1insn_patch_entry *p1;
+       struct sun4v_2insn_patch_entry *p2;
+
+       if (tlb_type != hypervisor)
+               return;
+
+       p1 = &__sun4v_1insn_patch;
+       while (p1 < &__sun4v_1insn_patch_end) {
+               unsigned long addr = p1->addr;
+
+               *(unsigned int *) (addr +  0) = p1->insn;
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  0));
+
+               p1++;
+       }
+
+       p2 = &__sun4v_2insn_patch;
+       while (p2 < &__sun4v_2insn_patch_end) {
+               unsigned long addr = p2->addr;
+
+               *(unsigned int *) (addr +  0) = p2->insns[0];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  0));
+
+               *(unsigned int *) (addr +  3) = p2->insns[1];
+               wmb();
+               __asm__ __volatile__("flush     %0" : : "r" (addr +  4));
+
+               p2++;
+       }
+}
+
 void __init setup_arch(char **cmdline_p)
 {
        /* Initialize PROM console and command line. */
@@ -503,6 +608,13 @@ void __init setup_arch(char **cmdline_p)
        /* Work out if we are starfire early on */
        check_if_starfire();
 
+       /* Now we know enough to patch the get_cpuid sequences
+        * used by trap code.
+        */
+       per_cpu_patch();
+
+       sun4v_patch();
+
        boot_flags_init(*cmdline_p);
 
        idprom_init();
@@ -516,7 +628,7 @@ void __init setup_arch(char **cmdline_p)
        rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
 #endif
 
-       init_task.thread_info->kregs = &fake_swapper_regs;
+       task_thread_info(&init_task)->kregs = &fake_swapper_regs;
 
 #ifdef CONFIG_IP_PNP
        if (!ic_set_manually) {
@@ -538,7 +650,12 @@ void __init setup_arch(char **cmdline_p)
        }
 #endif
 
+       smp_setup_cpu_possible_map();
+
        paging_init();
+
+       /* Get boot processor trap_block[] setup.  */
+       init_cur_cpu_trap();
 }
 
 static int __init set_preferred_console(void)
@@ -557,6 +674,8 @@ static int __init set_preferred_console(void)
                serial_console = 1;
        } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
                serial_console = 2;
+       } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
+               serial_console = 3;
        } else {
                prom_printf("Inconsistent console: "
                            "input %d, output %d\n",
@@ -583,6 +702,8 @@ extern void mmu_info(struct seq_file *);
 unsigned int dcache_parity_tl1_occurred;
 unsigned int icache_parity_tl1_occurred;
 
+static int ncpus_probed;
+
 static int show_cpuinfo(struct seq_file *m, void *__unused)
 {
        seq_printf(m, 
@@ -591,8 +712,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
                   "promlib\t\t: Version 3 Revision %d\n"
                   "prom\t\t: %d.%d.%d\n"
                   "type\t\t: sun4u\n"
-                  "ncpus probed\t: %ld\n"
-                  "ncpus active\t: %ld\n"
+                  "ncpus probed\t: %d\n"
+                  "ncpus active\t: %d\n"
                   "D$ parity tl1\t: %u\n"
                   "I$ parity tl1\t: %u\n"
 #ifndef CONFIG_SMP
@@ -606,8 +727,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
                   prom_prev >> 16,
                   (prom_prev >> 8) & 0xff,
                   prom_prev & 0xff,
-                  (long)num_possible_cpus(),
-                  (long)num_online_cpus(),
+                  ncpus_probed,
+                  num_online_cpus(),
                   dcache_parity_tl1_occurred,
                   icache_parity_tl1_occurred
 #ifndef CONFIG_SMP
@@ -673,6 +794,15 @@ static int __init topology_init(void)
        int i, err;
 
        err = -ENOMEM;
+
+       /* Count the number of physically present processors in
+        * the machine, even on uniprocessor, so that /proc/cpuinfo
+        * output is consistent with 2.4.x
+        */
+       ncpus_probed = 0;
+       while (!cpu_find_by_instance(ncpus_probed, NULL, NULL))
+               ncpus_probed++;
+
        for (i = 0; i < NR_CPUS; i++) {
                if (cpu_possible(i)) {
                        struct cpu *p = kmalloc(sizeof(*p), GFP_KERNEL);