1bbd0abdaSPaul Mackerras /* 2bbd0abdaSPaul Mackerras * Smp support for CHRP machines. 3bbd0abdaSPaul Mackerras * 4bbd0abdaSPaul Mackerras * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great 5bbd0abdaSPaul Mackerras * deal of code from the sparc and intel versions. 6bbd0abdaSPaul Mackerras * 7bbd0abdaSPaul Mackerras * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> 8bbd0abdaSPaul Mackerras * 9bbd0abdaSPaul Mackerras */ 10bbd0abdaSPaul Mackerras 11bbd0abdaSPaul Mackerras #include <linux/config.h> 12bbd0abdaSPaul Mackerras #include <linux/kernel.h> 13bbd0abdaSPaul Mackerras #include <linux/sched.h> 14bbd0abdaSPaul Mackerras #include <linux/smp.h> 15bbd0abdaSPaul Mackerras #include <linux/smp_lock.h> 16bbd0abdaSPaul Mackerras #include <linux/interrupt.h> 17bbd0abdaSPaul Mackerras #include <linux/kernel_stat.h> 18bbd0abdaSPaul Mackerras #include <linux/delay.h> 19bbd0abdaSPaul Mackerras #include <linux/init.h> 20bbd0abdaSPaul Mackerras #include <linux/spinlock.h> 21bbd0abdaSPaul Mackerras 22bbd0abdaSPaul Mackerras #include <asm/ptrace.h> 23bbd0abdaSPaul Mackerras #include <asm/atomic.h> 24bbd0abdaSPaul Mackerras #include <asm/irq.h> 25bbd0abdaSPaul Mackerras #include <asm/page.h> 26bbd0abdaSPaul Mackerras #include <asm/pgtable.h> 27bbd0abdaSPaul Mackerras #include <asm/sections.h> 28bbd0abdaSPaul Mackerras #include <asm/io.h> 29bbd0abdaSPaul Mackerras #include <asm/prom.h> 30bbd0abdaSPaul Mackerras #include <asm/smp.h> 31bbd0abdaSPaul Mackerras #include <asm/residual.h> 32bbd0abdaSPaul Mackerras #include <asm/time.h> 33bbd0abdaSPaul Mackerras #include <asm/open_pic.h> 34bbd0abdaSPaul Mackerras #include <asm/machdep.h> 35*80579e1fSPaul Mackerras #include <asm/smp.h> 36*80579e1fSPaul Mackerras #include <asm/mpic.h> 37bbd0abdaSPaul Mackerras 38bbd0abdaSPaul Mackerras extern unsigned long smp_chrp_cpu_nr; 39bbd0abdaSPaul Mackerras 40bbd0abdaSPaul Mackerras static int __init smp_chrp_probe(void) 41bbd0abdaSPaul Mackerras { 42*80579e1fSPaul Mackerras struct device_node *cpus = NULL; 43*80579e1fSPaul Mackerras unsigned int *reg; 44*80579e1fSPaul Mackerras int reglen; 45*80579e1fSPaul Mackerras int ncpus = 0; 46*80579e1fSPaul Mackerras int cpuid; 47*80579e1fSPaul Mackerras unsigned int phys; 48bbd0abdaSPaul Mackerras 49*80579e1fSPaul Mackerras /* Count CPUs in the device-tree */ 50*80579e1fSPaul Mackerras cpuid = 1; /* the boot cpu is logical cpu 0 */ 51*80579e1fSPaul Mackerras while ((cpus = of_find_node_by_type(cpus, "cpu")) != NULL) { 52*80579e1fSPaul Mackerras phys = ncpus; 53*80579e1fSPaul Mackerras reg = (unsigned int *) get_property(cpus, "reg", ®len); 54*80579e1fSPaul Mackerras if (reg && reglen >= sizeof(unsigned int)) 55*80579e1fSPaul Mackerras /* hmmm, not having a reg property would be bad */ 56*80579e1fSPaul Mackerras phys = *reg; 57*80579e1fSPaul Mackerras if (phys != boot_cpuid_phys) { 58*80579e1fSPaul Mackerras set_hard_smp_processor_id(cpuid, phys); 59*80579e1fSPaul Mackerras ++cpuid; 60*80579e1fSPaul Mackerras } 61*80579e1fSPaul Mackerras ++ncpus; 62*80579e1fSPaul Mackerras } 63*80579e1fSPaul Mackerras 64*80579e1fSPaul Mackerras printk(KERN_INFO "CHRP SMP probe found %d cpus\n", ncpus); 65*80579e1fSPaul Mackerras 66*80579e1fSPaul Mackerras /* Nothing more to do if less than 2 of them */ 67*80579e1fSPaul Mackerras if (ncpus <= 1) 68*80579e1fSPaul Mackerras return 1; 69*80579e1fSPaul Mackerras 70*80579e1fSPaul Mackerras mpic_request_ipis(); 71*80579e1fSPaul Mackerras 72*80579e1fSPaul Mackerras return ncpus; 73bbd0abdaSPaul Mackerras } 74bbd0abdaSPaul Mackerras 75bbd0abdaSPaul Mackerras static void __devinit smp_chrp_kick_cpu(int nr) 76bbd0abdaSPaul Mackerras { 77bbd0abdaSPaul Mackerras *(unsigned long *)KERNELBASE = nr; 78bbd0abdaSPaul Mackerras asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); 79bbd0abdaSPaul Mackerras } 80bbd0abdaSPaul Mackerras 81bbd0abdaSPaul Mackerras static void __devinit smp_chrp_setup_cpu(int cpu_nr) 82bbd0abdaSPaul Mackerras { 83*80579e1fSPaul Mackerras mpic_setup_this_cpu(); 84bbd0abdaSPaul Mackerras } 85bbd0abdaSPaul Mackerras 86bbd0abdaSPaul Mackerras static DEFINE_SPINLOCK(timebase_lock); 87bbd0abdaSPaul Mackerras static unsigned int timebase_upper = 0, timebase_lower = 0; 88bbd0abdaSPaul Mackerras 89bbd0abdaSPaul Mackerras void __devinit smp_chrp_give_timebase(void) 90bbd0abdaSPaul Mackerras { 91bbd0abdaSPaul Mackerras spin_lock(&timebase_lock); 92bbd0abdaSPaul Mackerras rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL); 93bbd0abdaSPaul Mackerras timebase_upper = get_tbu(); 94bbd0abdaSPaul Mackerras timebase_lower = get_tbl(); 95bbd0abdaSPaul Mackerras spin_unlock(&timebase_lock); 96bbd0abdaSPaul Mackerras 97bbd0abdaSPaul Mackerras while (timebase_upper || timebase_lower) 98bbd0abdaSPaul Mackerras barrier(); 99bbd0abdaSPaul Mackerras rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL); 100bbd0abdaSPaul Mackerras } 101bbd0abdaSPaul Mackerras 102bbd0abdaSPaul Mackerras void __devinit smp_chrp_take_timebase(void) 103bbd0abdaSPaul Mackerras { 104bbd0abdaSPaul Mackerras while (!(timebase_upper || timebase_lower)) 105bbd0abdaSPaul Mackerras barrier(); 106bbd0abdaSPaul Mackerras spin_lock(&timebase_lock); 107bbd0abdaSPaul Mackerras set_tb(timebase_upper, timebase_lower); 108bbd0abdaSPaul Mackerras timebase_upper = 0; 109bbd0abdaSPaul Mackerras timebase_lower = 0; 110bbd0abdaSPaul Mackerras spin_unlock(&timebase_lock); 111bbd0abdaSPaul Mackerras printk("CPU %i taken timebase\n", smp_processor_id()); 112bbd0abdaSPaul Mackerras } 113bbd0abdaSPaul Mackerras 114bbd0abdaSPaul Mackerras /* CHRP with openpic */ 115bbd0abdaSPaul Mackerras struct smp_ops_t chrp_smp_ops = { 116*80579e1fSPaul Mackerras .message_pass = smp_mpic_message_pass, 117bbd0abdaSPaul Mackerras .probe = smp_chrp_probe, 118bbd0abdaSPaul Mackerras .kick_cpu = smp_chrp_kick_cpu, 119bbd0abdaSPaul Mackerras .setup_cpu = smp_chrp_setup_cpu, 120bbd0abdaSPaul Mackerras .give_timebase = smp_chrp_give_timebase, 121bbd0abdaSPaul Mackerras .take_timebase = smp_chrp_take_timebase, 122bbd0abdaSPaul Mackerras }; 123