http://www.hht-eu.com/pls/hht/docs/F3140/bcm963xx_Speedport500V.0.09.04L.300L01.V27_c...
[bcm963xx.git] / kernel / linux / arch / mips / sgi-ip27 / ip27-init.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/config.h>
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/sched.h>
13 #include <linux/mmzone.h>       /* for numnodes */
14 #include <linux/mm.h>
15 #include <linux/module.h>
16 #include <linux/cpumask.h>
17 #include <asm/cpu.h>
18 #include <asm/io.h>
19 #include <asm/pgtable.h>
20 #include <asm/time.h>
21 #include <asm/sn/types.h>
22 #include <asm/sn/sn0/addrs.h>
23 #include <asm/sn/sn0/hubni.h>
24 #include <asm/sn/sn0/hubio.h>
25 #include <asm/sn/klconfig.h>
26 #include <asm/sn/ioc3.h>
27 #include <asm/mipsregs.h>
28 #include <asm/sn/gda.h>
29 #include <asm/sn/hub.h>
30 #include <asm/sn/intr.h>
31 #include <asm/current.h>
32 #include <asm/smp.h>
33 #include <asm/processor.h>
34 #include <asm/mmu_context.h>
35 #include <asm/thread_info.h>
36 #include <asm/sn/launch.h>
37 #include <asm/sn/sn_private.h>
38 #include <asm/sn/sn0/ip27.h>
39 #include <asm/sn/mapped_kernel.h>
40
41 #define CPU_NONE                (cpuid_t)-1
42
43 static DECLARE_BITMAP(hub_init_mask, MAX_COMPACT_NODES);
44 static hubreg_t region_mask;
45 static int      fine_mode;
46 static int router_distance;
47 nasid_t master_nasid = INVALID_NASID;
48
49 cnodeid_t       nasid_to_compact_node[MAX_NASIDS];
50 nasid_t         compact_to_nasid_node[MAX_COMPACT_NODES];
51 cnodeid_t       cpuid_to_compact_node[MAXCPUS];
52 char            node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
53
54 EXPORT_SYMBOL(nasid_to_compact_node);
55
56 static hubreg_t get_region(cnodeid_t cnode)
57 {
58         if (fine_mode)
59                 return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
60         else
61                 return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
62 }
63
64 static void gen_region_mask(hubreg_t *region_mask, int maxnodes)
65 {
66         cnodeid_t cnode;
67
68         (*region_mask) = 0;
69         for (cnode = 0; cnode < maxnodes; cnode++) {
70                 (*region_mask) |= 1ULL << get_region(cnode);
71         }
72 }
73
74 static int is_fine_dirmode(void)
75 {
76         return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
77                 >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
78 }
79
80 extern void pcibr_setup(cnodeid_t);
81
82 static __init void per_slice_init(cnodeid_t cnode, int slice)
83 {
84         struct slice_data *si = hub_data[cnode]->slice + slice;
85         int cpu = smp_processor_id();
86         int i;
87
88         for (i = 0; i < LEVELS_PER_SLICE; i++)
89                 si->level_to_irq[i] = -1;
90         /*
91          * Some interrupts are reserved by hardware or by software convention.
92          * Mark these as reserved right away so they won't be used accidently
93          * later.
94          */
95         for (i = 0; i <= BASE_PCI_IRQ; i++) {
96                 __set_bit(i, si->irq_alloc_mask);
97                 LOCAL_HUB_S(PI_INT_PEND_MOD, i);
98         }
99
100         __set_bit(IP_PEND0_6_63, si->irq_alloc_mask);
101         LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);
102
103         for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
104                 __set_bit(i, si->irq_alloc_mask + 1);
105                 LOCAL_HUB_S(PI_INT_PEND_MOD, i);
106         }
107
108         LOCAL_HUB_L(PI_INT_PEND0);
109
110         /*
111          * We use this so we can find the local hub's data as fast as only
112          * possible.
113          */
114         cpu_data[cpu].data = si;
115 }
116
117 extern void xtalk_probe_node(cnodeid_t nid);
118
119 void __init per_hub_init(cnodeid_t cnode)
120 {
121         struct hub_data *hub = HUB_DATA(cnode);
122         nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
123         int slice = LOCAL_HUB_L(PI_CPU_NUM);
124
125         cpu_set(smp_processor_id(), hub->h_cpus);
126
127         if (!test_and_set_bit(slice, &hub->slice_map))
128                 per_slice_init(cnode, slice);
129
130         if (test_and_set_bit(cnode, hub_init_mask))
131                 return;
132
133         /*
134          * Set CRB timeout at 5ms, (< PI timeout of 10ms)
135          */
136         REMOTE_HUB_S(nasid, IIO_ICTP, 0x800);
137         REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
138
139         hub_rtc_init(cnode);
140         xtalk_probe_node(cnode);
141
142 #ifdef CONFIG_REPLICATE_EXHANDLERS
143         /*
144          * If this is not a headless node initialization,
145          * copy over the caliased exception handlers.
146          */
147         if (get_compact_nodeid() == cnode) {
148                 extern char except_vec0, except_vec1_r4k;
149                 extern char except_vec2_generic, except_vec3_generic;
150
151                 memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
152                 memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80);
153                 memcpy((void *)KSEG0, &except_vec0, 0x80);
154                 memcpy((void *)KSEG0 + 0x080, &except_vec1_r4k, 0x80);
155                 memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80);
156                 memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x100);
157                 __flush_cache_all();
158         }
159 #endif
160 }
161
162 /*
163  * get_nasid() returns the physical node id number of the caller.
164  */
165 nasid_t
166 get_nasid(void)
167 {
168         return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
169                          >> NSRI_NODEID_SHFT);
170 }
171
172 /*
173  * Map the physical node id to a virtual node id (virtual node ids are contiguous).
174  */
175 cnodeid_t get_compact_nodeid(void)
176 {
177         return NASID_TO_COMPACT_NODEID(get_nasid());
178 }
179
180 #define rou_rflag       rou_flags
181
182 static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
183 {
184         klrou_t *router;
185         lboard_t *brd;
186         int     port;
187
188         if (router_a->rou_rflag == 1)
189                 return;
190
191         if (depth >= router_distance)
192                 return;
193
194         router_a->rou_rflag = 1;
195
196         for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
197                 if (router_a->rou_port[port].port_nasid == INVALID_NASID)
198                         continue;
199
200                 brd = (lboard_t *)NODE_OFFSET_TO_K0(
201                         router_a->rou_port[port].port_nasid,
202                         router_a->rou_port[port].port_offset);
203
204                 if (brd->brd_type == KLTYPE_ROUTER) {
205                         router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
206                         if (router == router_b) {
207                                 if (depth < router_distance)
208                                         router_distance = depth;
209                         }
210                         else
211                                 router_recurse(router, router_b, depth + 1);
212                 }
213         }
214
215         router_a->rou_rflag = 0;
216 }
217
218 int node_distance(nasid_t nasid_a, nasid_t nasid_b)
219 {
220         klrou_t *router, *router_a = NULL, *router_b = NULL;
221         lboard_t *brd, *dest_brd;
222         cnodeid_t cnode;
223         nasid_t nasid;
224         int port;
225
226         /* Figure out which routers nodes in question are connected to */
227         for (cnode = 0; cnode < numnodes; cnode++) {
228                 nasid = COMPACT_TO_NASID_NODEID(cnode);
229
230                 if (nasid == -1) continue;
231
232                 brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
233                                         KLTYPE_ROUTER);
234
235                 if (!brd)
236                         continue;
237
238                 do {
239                         if (brd->brd_flags & DUPLICATE_BOARD)
240                                 continue;
241
242                         router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
243                         router->rou_rflag = 0;
244
245                         for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
246                                 if (router->rou_port[port].port_nasid == INVALID_NASID)
247                                         continue;
248
249                                 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
250                                         router->rou_port[port].port_nasid,
251                                         router->rou_port[port].port_offset);
252
253                                 if (dest_brd->brd_type == KLTYPE_IP27) {
254                                         if (dest_brd->brd_nasid == nasid_a)
255                                                 router_a = router;
256                                         if (dest_brd->brd_nasid == nasid_b)
257                                                 router_b = router;
258                                 }
259                         }
260
261                 } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
262         }
263
264         if (router_a == NULL) {
265                 printk("node_distance: router_a NULL\n");
266                 return -1;
267         }
268         if (router_b == NULL) {
269                 printk("node_distance: router_b NULL\n");
270                 return -1;
271         }
272
273         if (nasid_a == nasid_b)
274                 return 0;
275
276         if (router_a == router_b)
277                 return 1;
278
279         router_distance = 100;
280         router_recurse(router_a, router_b, 2);
281
282         return router_distance;
283 }
284
285 static void init_topology_matrix(void)
286 {
287         nasid_t nasid, nasid2;
288         cnodeid_t row, col;
289
290         for (row = 0; row < MAX_COMPACT_NODES; row++)
291                 for (col = 0; col < MAX_COMPACT_NODES; col++)
292                         node_distances[row][col] = -1;
293
294         for (row = 0; row < numnodes; row++) {
295                 nasid = COMPACT_TO_NASID_NODEID(row);
296                 for (col = 0; col < numnodes; col++) {
297                         nasid2 = COMPACT_TO_NASID_NODEID(col);
298                         node_distances[row][col] = node_distance(nasid, nasid2);
299                 }
300         }
301 }
302
303 static void dump_topology(void)
304 {
305         nasid_t nasid;
306         cnodeid_t cnode;
307         lboard_t *brd, *dest_brd;
308         int port;
309         int router_num = 0;
310         klrou_t *router;
311         cnodeid_t row, col;
312
313         printk("************** Topology ********************\n");
314
315         printk("    ");
316         for (col = 0; col < numnodes; col++)
317                 printk("%02d ", col);
318         printk("\n");
319         for (row = 0; row < numnodes; row++) {
320                 printk("%02d  ", row);
321                 for (col = 0; col < numnodes; col++)
322                         printk("%2d ", node_distances[row][col]);
323                 printk("\n");
324         }
325
326         for (cnode = 0; cnode < numnodes; cnode++) {
327                 nasid = COMPACT_TO_NASID_NODEID(cnode);
328
329                 if (nasid == -1) continue;
330
331                 brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
332                                         KLTYPE_ROUTER);
333
334                 if (!brd)
335                         continue;
336
337                 do {
338                         if (brd->brd_flags & DUPLICATE_BOARD)
339                                 continue;
340                         printk("Router %d:", router_num);
341                         router_num++;
342
343                         router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
344
345                         for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
346                                 if (router->rou_port[port].port_nasid == INVALID_NASID)
347                                         continue;
348
349                                 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
350                                         router->rou_port[port].port_nasid,
351                                         router->rou_port[port].port_offset);
352
353                                 if (dest_brd->brd_type == KLTYPE_IP27)
354                                         printk(" %d", dest_brd->brd_nasid);
355                                 if (dest_brd->brd_type == KLTYPE_ROUTER)
356                                         printk(" r");
357                         }
358                         printk("\n");
359
360                 } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
361         }
362 }
363
364 void mlreset(void)
365 {
366         int i;
367
368         master_nasid = get_nasid();
369         fine_mode = is_fine_dirmode();
370
371         /*
372          * Probe for all CPUs - this creates the cpumask and sets up the
373          * mapping tables.  We need to do this as early as possible.
374          */
375 #ifdef CONFIG_SMP
376         cpu_node_probe();
377 #endif
378
379         init_topology_matrix();
380         dump_topology();
381
382         gen_region_mask(&region_mask, numnodes);
383
384         setup_replication_mask(numnodes);
385
386         /*
387          * Set all nodes' calias sizes to 8k
388          */
389         for (i = 0; i < numnodes; i++) {
390                 nasid_t nasid;
391
392                 nasid = COMPACT_TO_NASID_NODEID(i);
393
394                 /*
395                  * Always have node 0 in the region mask, otherwise
396                  * CALIAS accesses get exceptions since the hub
397                  * thinks it is a node 0 address.
398                  */
399                 REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
400 #ifdef CONFIG_REPLICATE_EXHANDLERS
401                 REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
402 #else
403                 REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
404 #endif
405
406 #ifdef LATER
407                 /*
408                  * Set up all hubs to have a big window pointing at
409                  * widget 0. Memory mode, widget 0, offset 0
410                  */
411                 REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
412                         ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
413                         (0 << IIO_ITTE_WIDGET_SHIFT)));
414 #endif
415         }
416 }
417
418 /* Extracted from the IOC3 meta driver.  FIXME.  */
419 static inline void ioc3_sio_init(void)
420 {
421         struct ioc3 *ioc3;
422         nasid_t nid;
423         long loops;
424
425         nid = get_nasid();
426         ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
427
428         ioc3->sscr_a = 0;                       /* PIO mode for uarta.  */
429         ioc3->sscr_b = 0;                       /* PIO mode for uartb.  */
430         ioc3->sio_iec = ~0;
431         ioc3->sio_ies = (SIO_IR_SA_INT | SIO_IR_SB_INT);
432
433         loops=1000000; while(loops--);
434         ioc3->sregs.uarta.iu_fcr = 0;
435         ioc3->sregs.uartb.iu_fcr = 0;
436         loops=1000000; while(loops--);
437 }
438
439 static inline void ioc3_eth_init(void)
440 {
441         struct ioc3 *ioc3;
442         nasid_t nid;
443
444         nid = get_nasid();
445         ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
446
447         ioc3->eier = 0;
448 }
449
450 void __init per_cpu_init(void)
451 {
452         cnodeid_t cnode = get_compact_nodeid();
453         int cpu = smp_processor_id();
454
455         clear_c0_status(ST0_IM);
456         per_hub_init(cnode);
457         cpu_time_init();
458         install_ipi();
459         /* Install our NMI handler if symmon hasn't installed one. */
460         install_cpu_nmi_handler(cputoslice(cpu));
461         set_c0_status(SRB_DEV0 | SRB_DEV1);
462 }
463
464 extern void ip27_setup_console(void);
465 extern void ip27_time_init(void);
466 extern void ip27_reboot_setup(void);
467
468 static int __init ip27_setup(void)
469 {
470         hubreg_t p, e, n_mode;
471         nasid_t nid;
472
473         ip27_setup_console();
474         ip27_reboot_setup();
475
476         /*
477          * hub_rtc init and cpu clock intr enabled for later calibrate_delay.
478          */
479         nid = get_nasid();
480         printk("IP27: Running on node %d.\n", nid);
481
482         p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1;
483         e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1;
484         printk("Node %d has %s primary CPU%s.\n", nid,
485                p ? "a" : "no",
486                e ? ", CPU is running" : "");
487
488         p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1;
489         e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1;
490         printk("Node %d has %s secondary CPU%s.\n", nid,
491                p ? "a" : "no",
492                e ? ", CPU is running" : "");
493
494         /*
495          * Try to catch kernel missconfigurations and give user an
496          * indication what option to select.
497          */
498         n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
499         printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
500 #ifdef CONFIG_SGI_SN0_N_MODE
501         if (!n_mode)
502                 panic("Kernel compiled for M mode.");
503 #else
504         if (n_mode)
505                 panic("Kernel compiled for N mode.");
506 #endif
507
508         ioc3_sio_init();
509         ioc3_eth_init();
510         per_cpu_init();
511
512         set_io_port_base(IO_BASE);
513
514         board_time_init = ip27_time_init;
515
516         return 0;
517 }
518
519 early_initcall(ip27_setup);