1103e2910289b206e685dee727b86fe8dd03a66e
[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 static void intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend,
126         int base_level)
127 {
128         volatile hubreg_t bits;
129         int i;
130
131         /* Check pending interrupts */
132         if ((bits = HUB_L(pend)) != 0)
133                 for (i = 0; i < N_INTPEND_BITS; i++)
134                         if (bits & (1 << i))
135                                 LOCAL_HUB_CLR_INTR(base_level + i);
136 }
137
138 static void intr_clear_all(nasid_t nasid)
139 {
140         REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
141         REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
142         REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
143         REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);
144         intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND0),
145                         INT_PEND0_BASELVL);
146         intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND1),
147                         INT_PEND1_BASELVL);
148 }
149
150 void __init prom_prepare_cpus(unsigned int max_cpus)
151 {
152         cnodeid_t       cnode;
153
154         for (cnode = 0; cnode < numnodes; cnode++)
155                 intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
156
157         replicate_kernel_text(numnodes);
158
159         /*
160          * Assumption to be fixed: we're always booted on logical / physical
161          * processor 0.  While we're always running on logical processor 0
162          * this still means this is physical processor zero; it might for
163          * example be disabled in the firwware.
164          */
165         alloc_cpupda(0, 0);
166 }
167
168 /*
169  * Launch a slave into smp_bootstrap().  It doesn't take an argument, and we
170  * set sp to the kernel stack of the newly created idle process, gp to the proc
171  * struct so that current_thread_info() will work.
172  */
173 void __init prom_boot_secondary(int cpu, struct task_struct *idle)
174 {
175         unsigned long gp = (unsigned long) idle->thread_info;
176         unsigned long sp = gp + THREAD_SIZE - 32;
177
178         LAUNCH_SLAVE(cputonasid(cpu),cputoslice(cpu),
179                 (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
180                 0, (void *) sp, (void *) gp);
181 }
182
183 void prom_init_secondary(void)
184 {
185         per_cpu_init();
186         local_irq_enable();
187 }
188
189 void __init prom_cpus_done(void)
190 {
191 }
192
193 void prom_smp_finish(void)
194 {
195 }
196
197 void core_send_ipi(int destid, unsigned int action)
198 {
199         int irq;
200
201         switch (action) {
202         case SMP_RESCHEDULE_YOURSELF:
203                 irq = CPU_RESCHED_A_IRQ;
204                 break;
205         case SMP_CALL_FUNCTION:
206                 irq = CPU_CALL_A_IRQ;
207                 break;
208         default:
209                 panic("sendintr");
210         }
211
212         irq += cputoslice(destid);
213
214         /*
215          * Convert the compact hub number to the NASID to get the correct
216          * part of the address space.  Then set the interrupt bit associated
217          * with the CPU we want to send the interrupt to.
218          */
219         REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cpu_to_node(destid)), irq);
220 }