ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / pmc-sierra / yosemite / smp.c
1 /*
2  * Copyright 2003 PMC-Sierra
3  * Author: Manish Lachwani (lachwani@pmc-sierra.com)
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19
20 #include <linux/init.h>
21 #include <linux/delay.h>
22 #include <linux/smp.h>
23 #include <linux/kernel_stat.h>
24
25 #include <asm/mmu_context.h>
26 #include <asm/trace.h>
27
28 extern void asmlinkage smp_bootstrap(void);
29
30 /*
31  * Send inter-processor interrupt
32  */
33 void core_send_ipi(int cpu, unsigned int action)
34 {
35         /*
36          * Generate and INTMSG so that it can be sent over to the destination CPU
37          * The INTMSG will put the STATUS bits based on the action desired
38          */
39         switch(action) {
40                 case SMP_RESCHEDULE_YOURSELF:
41                         /* Do nothing */
42                         break;
43                 case SMP_CALL_FUNCTION:
44                         if (cpu == 1)
45                                 *(volatile uint32_t *)(0xbb000a00) = 0x00610002;
46                         else
47                                 *(volatile uint32_t *)(0xbb000a00) = 0x00610001;
48                         break;
49
50                 default:
51                         panic("core_send_ipi \n");
52         }
53 }
54
55 /*
56  * Mailbox interrupt to handle IPI
57  */
58 void jaguar_mailbox_irq(struct pt_regs *regs)
59 {
60         int cpu = smp_processor_id();
61
62         /* SMP_CALL_FUNCTION */
63         smp_call_function_interrupt();
64 }
65
66 extern atomic_t cpus_booted;
67
68 void __init start_secondary(void)
69 {
70         unsigned int cpu = smp_processor_id();
71         extern atomic_t smp_commenced;
72
73         if (current->processor != 1) {
74                 printk("Impossible CPU %d \n", cpu);
75                 current->processor = 1;
76                 current->cpus_runnable = 1 << 1;
77                 cpu = current->processor;
78         }
79
80         if (current->mm)
81                 current->mm = NULL;
82
83         prom_init_secondary();
84         per_cpu_trap_init();
85
86         /*
87          * XXX parity protection should be folded in here when it's converted
88          * to an option instead of something based on .cputype
89          */
90         pgd_current[cpu] = init_mm.pgd;
91         cpu_data[cpu].udelay_val = loops_per_jiffy;
92         prom_smp_finish();
93         CPUMASK_SETB(cpu_online_map, cpu);
94         atomic_inc(&cpus_booted);
95         __flush_cache_all();
96
97         printk("Slave cpu booted successfully  \n");
98         *(volatile uint32_t *)(0xbb000a68) = 0x00000000;
99         *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
100
101         while (*(volatile uint32_t *)(0xbb000a68) != 0x00000000);
102
103         return cpu_idle();
104 }
105
106 void __init smp_boot_cpus(void)
107 {
108         int i;
109         int cur_cpu = 0;
110
111         smp_num_cpus = prom_setup_smp();
112         printk("Detected %d available CPUs \n", smp_num_cpus);
113
114         init_new_context(current, &init_mm);
115         current->processor = 0;
116         cpu_data[0].udelay_val = loops_per_jiffy;
117         cpu_data[0].asid_cache = ASID_FIRST_VERSION;
118         CPUMASK_CLRALL(cpu_online_map);
119         CPUMASK_SETB(cpu_online_map, 0);
120         atomic_set(&cpus_booted, 1);  /* Master CPU is already booted... */
121         init_idle();
122
123         __cpu_number_map[0] = 0;
124         __cpu_logical_map[0] = 0;
125
126         /*
127          * This loop attempts to compensate for "holes" in the CPU
128          * numbering.  It's overkill, but general.
129          */
130         for (i = 1; i < smp_num_cpus; ) {
131                 struct task_struct *p;
132                 struct pt_regs regs;
133                 int retval;
134                 printk("Starting CPU %d... \n", i);
135
136                 /* Spawn a new process normally.  Grab a pointer to
137                    its task struct so we can mess with it */
138                 do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
139
140                 p = init_task.prev_task;
141                 if (!p)
142                         panic("failed fork for CPU %d", i);
143
144                 /* This is current for the second processor */
145                 p->processor = i;
146                 p->cpus_runnable = 1 << i; /* we schedule the first task manually */
147                 p->thread.reg31 = (unsigned long) start_secondary;
148
149                 del_from_runqueue(p);
150                 unhash_process(p);
151                 init_tasks[i] = p;
152
153                 __flush_cache_all();
154
155                 do {
156                         /* Iterate until we find a CPU that comes up */
157                         cur_cpu++;
158                         retval = prom_boot_secondary(cur_cpu,
159                                             (unsigned long)p + KERNEL_STACK_SIZE - 32,
160                                             (unsigned long)p);
161
162                 } while (!retval && (cur_cpu < NR_CPUS));
163                 if (retval) {
164                         __cpu_number_map[cur_cpu] = i;
165                         __cpu_logical_map[i] = cur_cpu;
166                         i++;
167                 } else {
168                         panic("CPU discovery disaster");
169                 }
170         }
171
172         /* Local semaphore to both the CPUs */
173
174         *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
175         while (*(volatile uint32_t *)(0xbb000a68) != 0x00000000);
176
177         smp_threads_ready = 1;
178 }