ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / sgi-ip27 / ip27-smp.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General
3  * Public License.  See the file "COPYING" in the main directory of this
4  * archive for more details.
5  *
6  * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
7  * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
8  */
9 #include <linux/init.h>
10 #include <linux/sched.h>
11 #include <asm/page.h>
12 #include <asm/processor.h>
13 #include <asm/sn/arch.h>
14 #include <asm/sn/gda.h>
15 #include <asm/sn/intr.h>
16 #include <asm/sn/klconfig.h>
17 #include <asm/sn/launch.h>
18 #include <asm/sn/mapped_kernel.h>
19 #include <asm/sn/sn_private.h>
20 #include <asm/sn/types.h>
21 #include <asm/sn/sn0/hubpi.h>
22 #include <asm/sn/sn0/hubio.h>
23 #include <asm/sn/sn0/ip27.h>
24
25 /*
26  * Takes as first input the PROM assigned cpu id, and the kernel
27  * assigned cpu id as the second.
28  */
29 static void alloc_cpupda(cpuid_t cpu, int cpunum)
30 {
31         cnodeid_t node = get_cpu_cnode(cpu);
32         nasid_t nasid = COMPACT_TO_NASID_NODEID(node);
33
34         cputonasid(cpunum) = nasid;
35         cpu_data[cpunum].p_nodeid = node;
36         cputoslice(cpunum) = get_cpu_slice(cpu);
37 }
38
39 static nasid_t get_actual_nasid(lboard_t *brd)
40 {
41         klhub_t *hub;
42
43         if (!brd)
44                 return INVALID_NASID;
45
46         /* find out if we are a completely disabled brd. */
47         hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
48         if (!hub)
49                 return INVALID_NASID;
50         if (!(hub->hub_info.flags & KLINFO_ENABLE))     /* disabled node brd */
51                 return hub->hub_info.physid;
52         else
53                 return brd->brd_nasid;
54 }
55
56 static int do_cpumask(cnodeid_t cnode, nasid_t nasid, int highest)
57 {
58         static int tot_cpus_found = 0;
59         lboard_t *brd;
60         klcpu_t *acpu;
61         int cpus_found = 0;
62         cpuid_t cpuid;
63
64         brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
65
66         do {
67                 acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
68                 while (acpu) {
69                         cpuid = acpu->cpu_info.virtid;
70                         /* cnode is not valid for completely disabled brds */
71                         if (get_actual_nasid(brd) == brd->brd_nasid)
72                                 cpuid_to_compact_node[cpuid] = cnode;
73                         if (cpuid > highest)
74                                 highest = cpuid;
75                         /* Only let it join in if it's marked enabled */
76                         if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
77                             (tot_cpus_found != NR_CPUS)) {
78                                 cpu_set(cpuid, phys_cpu_present_map);
79                                 alloc_cpupda(cpuid, tot_cpus_found);
80                                 cpus_found++;
81                                 tot_cpus_found++;
82                         }
83                         acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
84                                                                 KLSTRUCT_CPU);
85                 }
86                 brd = KLCF_NEXT(brd);
87                 if (!brd)
88                         break;
89
90                 brd = find_lboard(brd, KLTYPE_IP27);
91         } while (brd);
92
93         return highest;
94 }
95
96 void cpu_node_probe(void)
97 {
98         int i, highest = 0;
99         gda_t *gdap = GDA;
100
101         /*
102          * Initialize the arrays to invalid nodeid (-1)
103          */
104         for (i = 0; i < MAX_COMPACT_NODES; i++)
105                 compact_to_nasid_node[i] = INVALID_NASID;
106         for (i = 0; i < MAX_NASIDS; i++)
107                 nasid_to_compact_node[i] = INVALID_CNODEID;
108         for (i = 0; i < MAXCPUS; i++)
109                 cpuid_to_compact_node[i] = INVALID_CNODEID;
110
111         numnodes = 0;
112         for (i = 0; i < MAX_COMPACT_NODES; i++) {
113                 nasid_t nasid = gdap->g_nasidtable[i];
114                 if (nasid == INVALID_NASID)
115                         break;
116                 compact_to_nasid_node[i] = nasid;
117                 nasid_to_compact_node[nasid] = i;
118                 numnodes++;
119                 highest = do_cpumask(i, nasid, highest);
120         }
121
122         printk("Discovered %d cpus on %d nodes\n", highest + 1, numnodes);
123 }
124
125 void __init prom_build_cpu_map(void)
126 {
127 }
128
129 static void intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend,
130         int base_level)
131 {
132         volatile hubreg_t bits;
133         int i;
134
135         /* Check pending interrupts */
136         if ((bits = HUB_L(pend)) != 0)
137                 for (i = 0; i < N_INTPEND_BITS; i++)
138                         if (bits & (1 << i))
139                                 LOCAL_HUB_CLR_INTR(base_level + i);
140 }
141
142 static void intr_clear_all(nasid_t nasid)
143 {
144         REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
145         REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
146         REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
147         REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);
148         intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND0),
149                         INT_PEND0_BASELVL);
150         intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND1),
151                         INT_PEND1_BASELVL);
152 }
153
154 void __init prom_prepare_cpus(unsigned int max_cpus)
155 {
156         cnodeid_t       cnode;
157
158         for (cnode = 0; cnode < numnodes; cnode++)
159                 intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
160
161         /* Master has already done per_cpu_init() */
162         install_ipi();
163
164         replicate_kernel_text(numnodes);
165
166         /*
167          * Assumption to be fixed: we're always booted on logical / physical
168          * processor 0.  While we're always running on logical processor 0
169          * this still means this is physical processor zero; it might for
170          * example be disabled in the firwware.
171          */
172         alloc_cpupda(0, 0);
173 }
174
175 /*
176  * Launch a slave into smp_bootstrap().  It doesn't take an argument, and we
177  * set sp to the kernel stack of the newly created idle process, gp to the proc
178  * struct so that current_thread_info() will work.
179  */
180 void __init prom_boot_secondary(int cpu, struct task_struct *idle)
181 {
182         unsigned long gp = (unsigned long) idle->thread_info;
183         unsigned long sp = gp + THREAD_SIZE - 32;
184
185         LAUNCH_SLAVE(cputonasid(cpu),cputoslice(cpu),
186                 (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
187                 0, (void *) sp, (void *) gp);
188 }
189
190 void prom_init_secondary(void)
191 {
192         per_cpu_init();
193         local_irq_enable();
194 }
195
196 void __init prom_cpus_done(void)
197 {
198 }
199
200 void prom_smp_finish(void)
201 {
202 }
203
204 void core_send_ipi(int destid, unsigned int action)
205 {
206         int irq;
207
208         switch (action) {
209         case SMP_RESCHEDULE_YOURSELF:
210                 irq = CPU_RESCHED_A_IRQ;
211                 break;
212         case SMP_CALL_FUNCTION:
213                 irq = CPU_CALL_A_IRQ;
214                 break;
215         default:
216                 panic("sendintr");
217         }
218
219         irq += cputoslice(destid);
220
221         /*
222          * Convert the compact hub number to the NASID to get the correct
223          * part of the address space.  Then set the interrupt bit associated
224          * with the CPU we want to send the interrupt to.
225          */
226         REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cpu_to_node(destid)), irq);
227 }