diff options
Diffstat (limited to 'arch/alpha/kernel/setup.c')
-rw-r--r-- | arch/alpha/kernel/setup.c | 1486 |
1 files changed, 1486 insertions, 0 deletions
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c new file mode 100644 index 000000000000..b4e5f8ff2b25 --- /dev/null +++ b/arch/alpha/kernel/setup.c | |||
@@ -0,0 +1,1486 @@ | |||
1 | /* | ||
2 | * linux/arch/alpha/kernel/setup.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* 2.3.x bootmem, 1999 Andrea Arcangeli <andrea@suse.de> */ | ||
8 | |||
9 | /* | ||
10 | * Bootup setup stuff. | ||
11 | */ | ||
12 | |||
13 | #include <linux/sched.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/unistd.h> | ||
18 | #include <linux/ptrace.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/user.h> | ||
21 | #include <linux/a.out.h> | ||
22 | #include <linux/tty.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/config.h> /* CONFIG_ALPHA_LCA etc */ | ||
25 | #include <linux/mc146818rtc.h> | ||
26 | #include <linux/console.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/bootmem.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <linux/seq_file.h> | ||
34 | #include <linux/root_dev.h> | ||
35 | #include <linux/initrd.h> | ||
36 | #include <linux/eisa.h> | ||
37 | #ifdef CONFIG_MAGIC_SYSRQ | ||
38 | #include <linux/sysrq.h> | ||
39 | #include <linux/reboot.h> | ||
40 | #endif | ||
41 | #include <linux/notifier.h> | ||
42 | #include <asm/setup.h> | ||
43 | #include <asm/io.h> | ||
44 | |||
45 | extern struct notifier_block *panic_notifier_list; | ||
46 | static int alpha_panic_event(struct notifier_block *, unsigned long, void *); | ||
47 | static struct notifier_block alpha_panic_block = { | ||
48 | alpha_panic_event, | ||
49 | NULL, | ||
50 | INT_MAX /* try to do it first */ | ||
51 | }; | ||
52 | |||
53 | #include <asm/uaccess.h> | ||
54 | #include <asm/pgtable.h> | ||
55 | #include <asm/system.h> | ||
56 | #include <asm/hwrpb.h> | ||
57 | #include <asm/dma.h> | ||
58 | #include <asm/io.h> | ||
59 | #include <asm/mmu_context.h> | ||
60 | #include <asm/console.h> | ||
61 | |||
62 | #include "proto.h" | ||
63 | #include "pci_impl.h" | ||
64 | |||
65 | |||
66 | struct hwrpb_struct *hwrpb; | ||
67 | unsigned long srm_hae; | ||
68 | |||
69 | int alpha_l1i_cacheshape; | ||
70 | int alpha_l1d_cacheshape; | ||
71 | int alpha_l2_cacheshape; | ||
72 | int alpha_l3_cacheshape; | ||
73 | |||
74 | #ifdef CONFIG_VERBOSE_MCHECK | ||
75 | /* 0=minimum, 1=verbose, 2=all */ | ||
76 | /* These can be overridden via the command line, ie "verbose_mcheck=2") */ | ||
77 | unsigned long alpha_verbose_mcheck = CONFIG_VERBOSE_MCHECK_ON; | ||
78 | #endif | ||
79 | |||
80 | /* Which processor we booted from. */ | ||
81 | int boot_cpuid; | ||
82 | |||
83 | /* | ||
84 | * Using SRM callbacks for initial console output. This works from | ||
85 | * setup_arch() time through the end of time_init(), as those places | ||
86 | * are under our (Alpha) control. | ||
87 | |||
88 | * "srmcons" specified in the boot command arguments allows us to | ||
89 | * see kernel messages during the period of time before the true | ||
90 | * console device is "registered" during console_init(). | ||
91 | * As of this version (2.5.59), console_init() will call | ||
92 | * disable_early_printk() as the last action before initializing | ||
93 | * the console drivers. That's the last possible time srmcons can be | ||
94 | * unregistered without interfering with console behavior. | ||
95 | * | ||
96 | * By default, OFF; set it with a bootcommand arg of "srmcons" or | ||
97 | * "console=srm". The meaning of these two args is: | ||
98 | * "srmcons" - early callback prints | ||
99 | * "console=srm" - full callback based console, including early prints | ||
100 | */ | ||
101 | int srmcons_output = 0; | ||
102 | |||
103 | /* Enforce a memory size limit; useful for testing. By default, none. */ | ||
104 | unsigned long mem_size_limit = 0; | ||
105 | |||
106 | /* Set AGP GART window size (0 means disabled). */ | ||
107 | unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE; | ||
108 | |||
109 | #ifdef CONFIG_ALPHA_GENERIC | ||
110 | struct alpha_machine_vector alpha_mv; | ||
111 | int alpha_using_srm; | ||
112 | #endif | ||
113 | |||
114 | #define N(a) (sizeof(a)/sizeof(a[0])) | ||
115 | |||
116 | static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long, | ||
117 | unsigned long); | ||
118 | static struct alpha_machine_vector *get_sysvec_byname(const char *); | ||
119 | static void get_sysnames(unsigned long, unsigned long, unsigned long, | ||
120 | char **, char **); | ||
121 | static void determine_cpu_caches (unsigned int); | ||
122 | |||
123 | static char command_line[COMMAND_LINE_SIZE]; | ||
124 | |||
125 | /* | ||
126 | * The format of "screen_info" is strange, and due to early | ||
127 | * i386-setup code. This is just enough to make the console | ||
128 | * code think we're on a VGA color display. | ||
129 | */ | ||
130 | |||
131 | struct screen_info screen_info = { | ||
132 | .orig_x = 0, | ||
133 | .orig_y = 25, | ||
134 | .orig_video_cols = 80, | ||
135 | .orig_video_lines = 25, | ||
136 | .orig_video_isVGA = 1, | ||
137 | .orig_video_points = 16 | ||
138 | }; | ||
139 | |||
140 | /* | ||
141 | * The direct map I/O window, if any. This should be the same | ||
142 | * for all busses, since it's used by virt_to_bus. | ||
143 | */ | ||
144 | |||
145 | unsigned long __direct_map_base; | ||
146 | unsigned long __direct_map_size; | ||
147 | |||
148 | /* | ||
149 | * Declare all of the machine vectors. | ||
150 | */ | ||
151 | |||
152 | /* GCC 2.7.2 (on alpha at least) is lame. It does not support either | ||
153 | __attribute__((weak)) or #pragma weak. Bypass it and talk directly | ||
154 | to the assembler. */ | ||
155 | |||
156 | #define WEAK(X) \ | ||
157 | extern struct alpha_machine_vector X; \ | ||
158 | asm(".weak "#X) | ||
159 | |||
160 | WEAK(alcor_mv); | ||
161 | WEAK(alphabook1_mv); | ||
162 | WEAK(avanti_mv); | ||
163 | WEAK(cabriolet_mv); | ||
164 | WEAK(clipper_mv); | ||
165 | WEAK(dp264_mv); | ||
166 | WEAK(eb164_mv); | ||
167 | WEAK(eb64p_mv); | ||
168 | WEAK(eb66_mv); | ||
169 | WEAK(eb66p_mv); | ||
170 | WEAK(eiger_mv); | ||
171 | WEAK(jensen_mv); | ||
172 | WEAK(lx164_mv); | ||
173 | WEAK(lynx_mv); | ||
174 | WEAK(marvel_ev7_mv); | ||
175 | WEAK(miata_mv); | ||
176 | WEAK(mikasa_mv); | ||
177 | WEAK(mikasa_primo_mv); | ||
178 | WEAK(monet_mv); | ||
179 | WEAK(nautilus_mv); | ||
180 | WEAK(noname_mv); | ||
181 | WEAK(noritake_mv); | ||
182 | WEAK(noritake_primo_mv); | ||
183 | WEAK(p2k_mv); | ||
184 | WEAK(pc164_mv); | ||
185 | WEAK(privateer_mv); | ||
186 | WEAK(rawhide_mv); | ||
187 | WEAK(ruffian_mv); | ||
188 | WEAK(rx164_mv); | ||
189 | WEAK(sable_mv); | ||
190 | WEAK(sable_gamma_mv); | ||
191 | WEAK(shark_mv); | ||
192 | WEAK(sx164_mv); | ||
193 | WEAK(takara_mv); | ||
194 | WEAK(titan_mv); | ||
195 | WEAK(webbrick_mv); | ||
196 | WEAK(wildfire_mv); | ||
197 | WEAK(xl_mv); | ||
198 | WEAK(xlt_mv); | ||
199 | |||
200 | #undef WEAK | ||
201 | |||
202 | /* | ||
203 | * I/O resources inherited from PeeCees. Except for perhaps the | ||
204 | * turbochannel alphas, everyone has these on some sort of SuperIO chip. | ||
205 | * | ||
206 | * ??? If this becomes less standard, move the struct out into the | ||
207 | * machine vector. | ||
208 | */ | ||
209 | |||
210 | static void __init | ||
211 | reserve_std_resources(void) | ||
212 | { | ||
213 | static struct resource standard_io_resources[] = { | ||
214 | { .name = "rtc", .start = -1, .end = -1 }, | ||
215 | { .name = "dma1", .start = 0x00, .end = 0x1f }, | ||
216 | { .name = "pic1", .start = 0x20, .end = 0x3f }, | ||
217 | { .name = "timer", .start = 0x40, .end = 0x5f }, | ||
218 | { .name = "keyboard", .start = 0x60, .end = 0x6f }, | ||
219 | { .name = "dma page reg", .start = 0x80, .end = 0x8f }, | ||
220 | { .name = "pic2", .start = 0xa0, .end = 0xbf }, | ||
221 | { .name = "dma2", .start = 0xc0, .end = 0xdf }, | ||
222 | }; | ||
223 | |||
224 | struct resource *io = &ioport_resource; | ||
225 | size_t i; | ||
226 | |||
227 | if (hose_head) { | ||
228 | struct pci_controller *hose; | ||
229 | for (hose = hose_head; hose; hose = hose->next) | ||
230 | if (hose->index == 0) { | ||
231 | io = hose->io_space; | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* Fix up for the Jensen's queer RTC placement. */ | ||
237 | standard_io_resources[0].start = RTC_PORT(0); | ||
238 | standard_io_resources[0].end = RTC_PORT(0) + 0x10; | ||
239 | |||
240 | for (i = 0; i < N(standard_io_resources); ++i) | ||
241 | request_resource(io, standard_io_resources+i); | ||
242 | } | ||
243 | |||
244 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
245 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
246 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
247 | #define PFN_MAX PFN_DOWN(0x80000000) | ||
248 | #define for_each_mem_cluster(memdesc, cluster, i) \ | ||
249 | for ((cluster) = (memdesc)->cluster, (i) = 0; \ | ||
250 | (i) < (memdesc)->numclusters; (i)++, (cluster)++) | ||
251 | |||
252 | static unsigned long __init | ||
253 | get_mem_size_limit(char *s) | ||
254 | { | ||
255 | unsigned long end = 0; | ||
256 | char *from = s; | ||
257 | |||
258 | end = simple_strtoul(from, &from, 0); | ||
259 | if ( *from == 'K' || *from == 'k' ) { | ||
260 | end = end << 10; | ||
261 | from++; | ||
262 | } else if ( *from == 'M' || *from == 'm' ) { | ||
263 | end = end << 20; | ||
264 | from++; | ||
265 | } else if ( *from == 'G' || *from == 'g' ) { | ||
266 | end = end << 30; | ||
267 | from++; | ||
268 | } | ||
269 | return end >> PAGE_SHIFT; /* Return the PFN of the limit. */ | ||
270 | } | ||
271 | |||
272 | #ifdef CONFIG_BLK_DEV_INITRD | ||
273 | void * __init | ||
274 | move_initrd(unsigned long mem_limit) | ||
275 | { | ||
276 | void *start; | ||
277 | unsigned long size; | ||
278 | |||
279 | size = initrd_end - initrd_start; | ||
280 | start = __alloc_bootmem(PAGE_ALIGN(size), PAGE_SIZE, 0); | ||
281 | if (!start || __pa(start) + size > mem_limit) { | ||
282 | initrd_start = initrd_end = 0; | ||
283 | return NULL; | ||
284 | } | ||
285 | memmove(start, (void *)initrd_start, size); | ||
286 | initrd_start = (unsigned long)start; | ||
287 | initrd_end = initrd_start + size; | ||
288 | printk("initrd moved to %p\n", start); | ||
289 | return start; | ||
290 | } | ||
291 | #endif | ||
292 | |||
293 | #ifndef CONFIG_DISCONTIGMEM | ||
294 | static void __init | ||
295 | setup_memory(void *kernel_end) | ||
296 | { | ||
297 | struct memclust_struct * cluster; | ||
298 | struct memdesc_struct * memdesc; | ||
299 | unsigned long start_kernel_pfn, end_kernel_pfn; | ||
300 | unsigned long bootmap_size, bootmap_pages, bootmap_start; | ||
301 | unsigned long start, end; | ||
302 | unsigned long i; | ||
303 | |||
304 | /* Find free clusters, and init and free the bootmem accordingly. */ | ||
305 | memdesc = (struct memdesc_struct *) | ||
306 | (hwrpb->mddt_offset + (unsigned long) hwrpb); | ||
307 | |||
308 | for_each_mem_cluster(memdesc, cluster, i) { | ||
309 | printk("memcluster %lu, usage %01lx, start %8lu, end %8lu\n", | ||
310 | i, cluster->usage, cluster->start_pfn, | ||
311 | cluster->start_pfn + cluster->numpages); | ||
312 | |||
313 | /* Bit 0 is console/PALcode reserved. Bit 1 is | ||
314 | non-volatile memory -- we might want to mark | ||
315 | this for later. */ | ||
316 | if (cluster->usage & 3) | ||
317 | continue; | ||
318 | |||
319 | end = cluster->start_pfn + cluster->numpages; | ||
320 | if (end > max_low_pfn) | ||
321 | max_low_pfn = end; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Except for the NUMA systems (wildfire, marvel) all of the | ||
326 | * Alpha systems we run on support 32GB of memory or less. | ||
327 | * Since the NUMA systems introduce large holes in memory addressing, | ||
328 | * we can get into a situation where there is not enough contiguous | ||
329 | * memory for the memory map. | ||
330 | * | ||
331 | * Limit memory to the first 32GB to limit the NUMA systems to | ||
332 | * memory on their first node (wildfire) or 2 (marvel) to avoid | ||
333 | * not being able to produce the memory map. In order to access | ||
334 | * all of the memory on the NUMA systems, build with discontiguous | ||
335 | * memory support. | ||
336 | * | ||
337 | * If the user specified a memory limit, let that memory limit stand. | ||
338 | */ | ||
339 | if (!mem_size_limit) | ||
340 | mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT; | ||
341 | |||
342 | if (mem_size_limit && max_low_pfn >= mem_size_limit) | ||
343 | { | ||
344 | printk("setup: forcing memory size to %ldK (from %ldK).\n", | ||
345 | mem_size_limit << (PAGE_SHIFT - 10), | ||
346 | max_low_pfn << (PAGE_SHIFT - 10)); | ||
347 | max_low_pfn = mem_size_limit; | ||
348 | } | ||
349 | |||
350 | /* Find the bounds of kernel memory. */ | ||
351 | start_kernel_pfn = PFN_DOWN(KERNEL_START_PHYS); | ||
352 | end_kernel_pfn = PFN_UP(virt_to_phys(kernel_end)); | ||
353 | bootmap_start = -1; | ||
354 | |||
355 | try_again: | ||
356 | if (max_low_pfn <= end_kernel_pfn) | ||
357 | panic("not enough memory to boot"); | ||
358 | |||
359 | /* We need to know how many physically contiguous pages | ||
360 | we'll need for the bootmap. */ | ||
361 | bootmap_pages = bootmem_bootmap_pages(max_low_pfn); | ||
362 | |||
363 | /* Now find a good region where to allocate the bootmap. */ | ||
364 | for_each_mem_cluster(memdesc, cluster, i) { | ||
365 | if (cluster->usage & 3) | ||
366 | continue; | ||
367 | |||
368 | start = cluster->start_pfn; | ||
369 | end = start + cluster->numpages; | ||
370 | if (start >= max_low_pfn) | ||
371 | continue; | ||
372 | if (end > max_low_pfn) | ||
373 | end = max_low_pfn; | ||
374 | if (start < start_kernel_pfn) { | ||
375 | if (end > end_kernel_pfn | ||
376 | && end - end_kernel_pfn >= bootmap_pages) { | ||
377 | bootmap_start = end_kernel_pfn; | ||
378 | break; | ||
379 | } else if (end > start_kernel_pfn) | ||
380 | end = start_kernel_pfn; | ||
381 | } else if (start < end_kernel_pfn) | ||
382 | start = end_kernel_pfn; | ||
383 | if (end - start >= bootmap_pages) { | ||
384 | bootmap_start = start; | ||
385 | break; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | if (bootmap_start == ~0UL) { | ||
390 | max_low_pfn >>= 1; | ||
391 | goto try_again; | ||
392 | } | ||
393 | |||
394 | /* Allocate the bootmap and mark the whole MM as reserved. */ | ||
395 | bootmap_size = init_bootmem(bootmap_start, max_low_pfn); | ||
396 | |||
397 | /* Mark the free regions. */ | ||
398 | for_each_mem_cluster(memdesc, cluster, i) { | ||
399 | if (cluster->usage & 3) | ||
400 | continue; | ||
401 | |||
402 | start = cluster->start_pfn; | ||
403 | end = cluster->start_pfn + cluster->numpages; | ||
404 | if (start >= max_low_pfn) | ||
405 | continue; | ||
406 | if (end > max_low_pfn) | ||
407 | end = max_low_pfn; | ||
408 | if (start < start_kernel_pfn) { | ||
409 | if (end > end_kernel_pfn) { | ||
410 | free_bootmem(PFN_PHYS(start), | ||
411 | (PFN_PHYS(start_kernel_pfn) | ||
412 | - PFN_PHYS(start))); | ||
413 | printk("freeing pages %ld:%ld\n", | ||
414 | start, start_kernel_pfn); | ||
415 | start = end_kernel_pfn; | ||
416 | } else if (end > start_kernel_pfn) | ||
417 | end = start_kernel_pfn; | ||
418 | } else if (start < end_kernel_pfn) | ||
419 | start = end_kernel_pfn; | ||
420 | if (start >= end) | ||
421 | continue; | ||
422 | |||
423 | free_bootmem(PFN_PHYS(start), PFN_PHYS(end) - PFN_PHYS(start)); | ||
424 | printk("freeing pages %ld:%ld\n", start, end); | ||
425 | } | ||
426 | |||
427 | /* Reserve the bootmap memory. */ | ||
428 | reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size); | ||
429 | printk("reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size)); | ||
430 | |||
431 | #ifdef CONFIG_BLK_DEV_INITRD | ||
432 | initrd_start = INITRD_START; | ||
433 | if (initrd_start) { | ||
434 | initrd_end = initrd_start+INITRD_SIZE; | ||
435 | printk("Initial ramdisk at: 0x%p (%lu bytes)\n", | ||
436 | (void *) initrd_start, INITRD_SIZE); | ||
437 | |||
438 | if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { | ||
439 | if (!move_initrd(PFN_PHYS(max_low_pfn))) | ||
440 | printk("initrd extends beyond end of memory " | ||
441 | "(0x%08lx > 0x%p)\ndisabling initrd\n", | ||
442 | initrd_end, | ||
443 | phys_to_virt(PFN_PHYS(max_low_pfn))); | ||
444 | } else { | ||
445 | reserve_bootmem(virt_to_phys((void *)initrd_start), | ||
446 | INITRD_SIZE); | ||
447 | } | ||
448 | } | ||
449 | #endif /* CONFIG_BLK_DEV_INITRD */ | ||
450 | } | ||
451 | #else | ||
452 | extern void setup_memory(void *); | ||
453 | #endif /* !CONFIG_DISCONTIGMEM */ | ||
454 | |||
455 | int __init | ||
456 | page_is_ram(unsigned long pfn) | ||
457 | { | ||
458 | struct memclust_struct * cluster; | ||
459 | struct memdesc_struct * memdesc; | ||
460 | unsigned long i; | ||
461 | |||
462 | memdesc = (struct memdesc_struct *) | ||
463 | (hwrpb->mddt_offset + (unsigned long) hwrpb); | ||
464 | for_each_mem_cluster(memdesc, cluster, i) | ||
465 | { | ||
466 | if (pfn >= cluster->start_pfn && | ||
467 | pfn < cluster->start_pfn + cluster->numpages) { | ||
468 | return (cluster->usage & 3) ? 0 : 1; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | #undef PFN_UP | ||
476 | #undef PFN_DOWN | ||
477 | #undef PFN_PHYS | ||
478 | #undef PFN_MAX | ||
479 | |||
480 | void __init | ||
481 | setup_arch(char **cmdline_p) | ||
482 | { | ||
483 | extern char _end[]; | ||
484 | |||
485 | struct alpha_machine_vector *vec = NULL; | ||
486 | struct percpu_struct *cpu; | ||
487 | char *type_name, *var_name, *p; | ||
488 | void *kernel_end = _end; /* end of kernel */ | ||
489 | char *args = command_line; | ||
490 | |||
491 | hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); | ||
492 | boot_cpuid = hard_smp_processor_id(); | ||
493 | |||
494 | /* | ||
495 | * Pre-process the system type to make sure it will be valid. | ||
496 | * | ||
497 | * This may restore real CABRIO and EB66+ family names, ie | ||
498 | * EB64+ and EB66. | ||
499 | * | ||
500 | * Oh, and "white box" AS800 (aka DIGITAL Server 3000 series) | ||
501 | * and AS1200 (DIGITAL Server 5000 series) have the type as | ||
502 | * the negative of the real one. | ||
503 | */ | ||
504 | if ((long)hwrpb->sys_type < 0) { | ||
505 | hwrpb->sys_type = -((long)hwrpb->sys_type); | ||
506 | hwrpb_update_checksum(hwrpb); | ||
507 | } | ||
508 | |||
509 | /* Register a call for panic conditions. */ | ||
510 | notifier_chain_register(&panic_notifier_list, &alpha_panic_block); | ||
511 | |||
512 | #ifdef CONFIG_ALPHA_GENERIC | ||
513 | /* Assume that we've booted from SRM if we haven't booted from MILO. | ||
514 | Detect the later by looking for "MILO" in the system serial nr. */ | ||
515 | alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; | ||
516 | #endif | ||
517 | |||
518 | /* If we are using SRM, we want to allow callbacks | ||
519 | as early as possible, so do this NOW, and then | ||
520 | they should work immediately thereafter. | ||
521 | */ | ||
522 | kernel_end = callback_init(kernel_end); | ||
523 | |||
524 | /* | ||
525 | * Locate the command line. | ||
526 | */ | ||
527 | /* Hack for Jensen... since we're restricted to 8 or 16 chars for | ||
528 | boot flags depending on the boot mode, we need some shorthand. | ||
529 | This should do for installation. */ | ||
530 | if (strcmp(COMMAND_LINE, "INSTALL") == 0) { | ||
531 | strlcpy(command_line, "root=/dev/fd0 load_ramdisk=1", sizeof command_line); | ||
532 | } else { | ||
533 | strlcpy(command_line, COMMAND_LINE, sizeof command_line); | ||
534 | } | ||
535 | strcpy(saved_command_line, command_line); | ||
536 | *cmdline_p = command_line; | ||
537 | |||
538 | /* | ||
539 | * Process command-line arguments. | ||
540 | */ | ||
541 | while ((p = strsep(&args, " \t")) != NULL) { | ||
542 | if (!*p) continue; | ||
543 | if (strncmp(p, "alpha_mv=", 9) == 0) { | ||
544 | vec = get_sysvec_byname(p+9); | ||
545 | continue; | ||
546 | } | ||
547 | if (strncmp(p, "cycle=", 6) == 0) { | ||
548 | est_cycle_freq = simple_strtol(p+6, NULL, 0); | ||
549 | continue; | ||
550 | } | ||
551 | if (strncmp(p, "mem=", 4) == 0) { | ||
552 | mem_size_limit = get_mem_size_limit(p+4); | ||
553 | continue; | ||
554 | } | ||
555 | if (strncmp(p, "srmcons", 7) == 0) { | ||
556 | srmcons_output |= 1; | ||
557 | continue; | ||
558 | } | ||
559 | if (strncmp(p, "console=srm", 11) == 0) { | ||
560 | srmcons_output |= 2; | ||
561 | continue; | ||
562 | } | ||
563 | if (strncmp(p, "gartsize=", 9) == 0) { | ||
564 | alpha_agpgart_size = | ||
565 | get_mem_size_limit(p+9) << PAGE_SHIFT; | ||
566 | continue; | ||
567 | } | ||
568 | #ifdef CONFIG_VERBOSE_MCHECK | ||
569 | if (strncmp(p, "verbose_mcheck=", 15) == 0) { | ||
570 | alpha_verbose_mcheck = simple_strtol(p+15, NULL, 0); | ||
571 | continue; | ||
572 | } | ||
573 | #endif | ||
574 | } | ||
575 | |||
576 | /* Replace the command line, now that we've killed it with strsep. */ | ||
577 | strcpy(command_line, saved_command_line); | ||
578 | |||
579 | /* If we want SRM console printk echoing early, do it now. */ | ||
580 | if (alpha_using_srm && srmcons_output) { | ||
581 | register_srm_console(); | ||
582 | |||
583 | /* | ||
584 | * If "console=srm" was specified, clear the srmcons_output | ||
585 | * flag now so that time.c won't unregister_srm_console | ||
586 | */ | ||
587 | if (srmcons_output & 2) | ||
588 | srmcons_output = 0; | ||
589 | } | ||
590 | |||
591 | #ifdef CONFIG_MAGIC_SYSRQ | ||
592 | /* If we're using SRM, make sysrq-b halt back to the prom, | ||
593 | not auto-reboot. */ | ||
594 | if (alpha_using_srm) { | ||
595 | struct sysrq_key_op *op = __sysrq_get_key_op('b'); | ||
596 | op->handler = (void *) machine_halt; | ||
597 | } | ||
598 | #endif | ||
599 | |||
600 | /* | ||
601 | * Identify and reconfigure for the current system. | ||
602 | */ | ||
603 | cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); | ||
604 | |||
605 | get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, | ||
606 | cpu->type, &type_name, &var_name); | ||
607 | if (*var_name == '0') | ||
608 | var_name = ""; | ||
609 | |||
610 | if (!vec) { | ||
611 | vec = get_sysvec(hwrpb->sys_type, hwrpb->sys_variation, | ||
612 | cpu->type); | ||
613 | } | ||
614 | |||
615 | if (!vec) { | ||
616 | panic("Unsupported system type: %s%s%s (%ld %ld)\n", | ||
617 | type_name, (*var_name ? " variation " : ""), var_name, | ||
618 | hwrpb->sys_type, hwrpb->sys_variation); | ||
619 | } | ||
620 | if (vec != &alpha_mv) { | ||
621 | alpha_mv = *vec; | ||
622 | } | ||
623 | |||
624 | printk("Booting " | ||
625 | #ifdef CONFIG_ALPHA_GENERIC | ||
626 | "GENERIC " | ||
627 | #endif | ||
628 | "on %s%s%s using machine vector %s from %s\n", | ||
629 | type_name, (*var_name ? " variation " : ""), | ||
630 | var_name, alpha_mv.vector_name, | ||
631 | (alpha_using_srm ? "SRM" : "MILO")); | ||
632 | |||
633 | printk("Major Options: " | ||
634 | #ifdef CONFIG_SMP | ||
635 | "SMP " | ||
636 | #endif | ||
637 | #ifdef CONFIG_ALPHA_EV56 | ||
638 | "EV56 " | ||
639 | #endif | ||
640 | #ifdef CONFIG_ALPHA_EV67 | ||
641 | "EV67 " | ||
642 | #endif | ||
643 | #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS | ||
644 | "LEGACY_START " | ||
645 | #endif | ||
646 | #ifdef CONFIG_VERBOSE_MCHECK | ||
647 | "VERBOSE_MCHECK " | ||
648 | #endif | ||
649 | |||
650 | #ifdef CONFIG_DISCONTIGMEM | ||
651 | "DISCONTIGMEM " | ||
652 | #ifdef CONFIG_NUMA | ||
653 | "NUMA " | ||
654 | #endif | ||
655 | #endif | ||
656 | |||
657 | #ifdef CONFIG_DEBUG_SPINLOCK | ||
658 | "DEBUG_SPINLOCK " | ||
659 | #endif | ||
660 | #ifdef CONFIG_MAGIC_SYSRQ | ||
661 | "MAGIC_SYSRQ " | ||
662 | #endif | ||
663 | "\n"); | ||
664 | |||
665 | printk("Command line: %s\n", command_line); | ||
666 | |||
667 | /* | ||
668 | * Sync up the HAE. | ||
669 | * Save the SRM's current value for restoration. | ||
670 | */ | ||
671 | srm_hae = *alpha_mv.hae_register; | ||
672 | __set_hae(alpha_mv.hae_cache); | ||
673 | |||
674 | /* Reset enable correctable error reports. */ | ||
675 | wrmces(0x7); | ||
676 | |||
677 | /* Find our memory. */ | ||
678 | setup_memory(kernel_end); | ||
679 | |||
680 | /* First guess at cpu cache sizes. Do this before init_arch. */ | ||
681 | determine_cpu_caches(cpu->type); | ||
682 | |||
683 | /* Initialize the machine. Usually has to do with setting up | ||
684 | DMA windows and the like. */ | ||
685 | if (alpha_mv.init_arch) | ||
686 | alpha_mv.init_arch(); | ||
687 | |||
688 | /* Reserve standard resources. */ | ||
689 | reserve_std_resources(); | ||
690 | |||
691 | /* | ||
692 | * Give us a default console. TGA users will see nothing until | ||
693 | * chr_dev_init is called, rather late in the boot sequence. | ||
694 | */ | ||
695 | |||
696 | #ifdef CONFIG_VT | ||
697 | #if defined(CONFIG_VGA_CONSOLE) | ||
698 | conswitchp = &vga_con; | ||
699 | #elif defined(CONFIG_DUMMY_CONSOLE) | ||
700 | conswitchp = &dummy_con; | ||
701 | #endif | ||
702 | #endif | ||
703 | |||
704 | /* Default root filesystem to sda2. */ | ||
705 | ROOT_DEV = Root_SDA2; | ||
706 | |||
707 | #ifdef CONFIG_EISA | ||
708 | /* FIXME: only set this when we actually have EISA in this box? */ | ||
709 | EISA_bus = 1; | ||
710 | #endif | ||
711 | |||
712 | /* | ||
713 | * Check ASN in HWRPB for validity, report if bad. | ||
714 | * FIXME: how was this failing? Should we trust it instead, | ||
715 | * and copy the value into alpha_mv.max_asn? | ||
716 | */ | ||
717 | |||
718 | if (hwrpb->max_asn != MAX_ASN) { | ||
719 | printk("Max ASN from HWRPB is bad (0x%lx)\n", hwrpb->max_asn); | ||
720 | } | ||
721 | |||
722 | /* | ||
723 | * Identify the flock of penguins. | ||
724 | */ | ||
725 | |||
726 | #ifdef CONFIG_SMP | ||
727 | setup_smp(); | ||
728 | #endif | ||
729 | paging_init(); | ||
730 | } | ||
731 | |||
732 | void __init | ||
733 | disable_early_printk(void) | ||
734 | { | ||
735 | if (alpha_using_srm && srmcons_output) { | ||
736 | unregister_srm_console(); | ||
737 | srmcons_output = 0; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | static char sys_unknown[] = "Unknown"; | ||
742 | static char systype_names[][16] = { | ||
743 | "0", | ||
744 | "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen", | ||
745 | "Pelican", "Morgan", "Sable", "Medulla", "Noname", | ||
746 | "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind", | ||
747 | "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", | ||
748 | "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", | ||
749 | "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", | ||
750 | "Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan", "Marvel" | ||
751 | }; | ||
752 | |||
753 | static char unofficial_names[][8] = {"100", "Ruffian"}; | ||
754 | |||
755 | static char api_names[][16] = {"200", "Nautilus"}; | ||
756 | |||
757 | static char eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164", "RX164"}; | ||
758 | static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,4}; | ||
759 | |||
760 | static char alcor_names[][16] = {"Alcor", "Maverick", "Bret"}; | ||
761 | static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2}; | ||
762 | |||
763 | static char eb64p_names[][16] = {"EB64+", "Cabriolet", "AlphaPCI64"}; | ||
764 | static int eb64p_indices[] = {0,0,1,2}; | ||
765 | |||
766 | static char eb66_names[][8] = {"EB66", "EB66+"}; | ||
767 | static int eb66_indices[] = {0,0,1}; | ||
768 | |||
769 | static char marvel_names[][16] = { | ||
770 | "Marvel/EV7" | ||
771 | }; | ||
772 | static int marvel_indices[] = { 0 }; | ||
773 | |||
774 | static char rawhide_names[][16] = { | ||
775 | "Dodge", "Wrangler", "Durango", "Tincup", "DaVinci" | ||
776 | }; | ||
777 | static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; | ||
778 | |||
779 | static char titan_names[][16] = { | ||
780 | "DEFAULT", "Privateer", "Falcon", "Granite" | ||
781 | }; | ||
782 | static int titan_indices[] = {0,1,2,2,3}; | ||
783 | |||
784 | static char tsunami_names[][16] = { | ||
785 | "0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper", | ||
786 | "Goldrush", "Webbrick", "Catamaran", "Brisbane", "Melbourne", | ||
787 | "Flying Clipper", "Shark" | ||
788 | }; | ||
789 | static int tsunami_indices[] = {0,1,2,3,4,5,6,7,8,9,10,11,12}; | ||
790 | |||
791 | static struct alpha_machine_vector * __init | ||
792 | get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu) | ||
793 | { | ||
794 | static struct alpha_machine_vector *systype_vecs[] __initdata = | ||
795 | { | ||
796 | NULL, /* 0 */ | ||
797 | NULL, /* ADU */ | ||
798 | NULL, /* Cobra */ | ||
799 | NULL, /* Ruby */ | ||
800 | NULL, /* Flamingo */ | ||
801 | NULL, /* Mannequin */ | ||
802 | &jensen_mv, | ||
803 | NULL, /* Pelican */ | ||
804 | NULL, /* Morgan */ | ||
805 | NULL, /* Sable -- see below. */ | ||
806 | NULL, /* Medulla */ | ||
807 | &noname_mv, | ||
808 | NULL, /* Turbolaser */ | ||
809 | &avanti_mv, | ||
810 | NULL, /* Mustang */ | ||
811 | NULL, /* Alcor, Bret, Maverick. HWRPB inaccurate? */ | ||
812 | NULL, /* Tradewind */ | ||
813 | NULL, /* Mikasa -- see below. */ | ||
814 | NULL, /* EB64 */ | ||
815 | NULL, /* EB66 -- see variation. */ | ||
816 | NULL, /* EB64+ -- see variation. */ | ||
817 | &alphabook1_mv, | ||
818 | &rawhide_mv, | ||
819 | NULL, /* K2 */ | ||
820 | &lynx_mv, /* Lynx */ | ||
821 | &xl_mv, | ||
822 | NULL, /* EB164 -- see variation. */ | ||
823 | NULL, /* Noritake -- see below. */ | ||
824 | NULL, /* Cortex */ | ||
825 | NULL, /* 29 */ | ||
826 | &miata_mv, | ||
827 | NULL, /* XXM */ | ||
828 | &takara_mv, | ||
829 | NULL, /* Yukon */ | ||
830 | NULL, /* Tsunami -- see variation. */ | ||
831 | &wildfire_mv, /* Wildfire */ | ||
832 | NULL, /* CUSCO */ | ||
833 | &eiger_mv, /* Eiger */ | ||
834 | NULL, /* Titan */ | ||
835 | NULL, /* Marvel */ | ||
836 | }; | ||
837 | |||
838 | static struct alpha_machine_vector *unofficial_vecs[] __initdata = | ||
839 | { | ||
840 | NULL, /* 100 */ | ||
841 | &ruffian_mv, | ||
842 | }; | ||
843 | |||
844 | static struct alpha_machine_vector *api_vecs[] __initdata = | ||
845 | { | ||
846 | NULL, /* 200 */ | ||
847 | &nautilus_mv, | ||
848 | }; | ||
849 | |||
850 | static struct alpha_machine_vector *alcor_vecs[] __initdata = | ||
851 | { | ||
852 | &alcor_mv, &xlt_mv, &xlt_mv | ||
853 | }; | ||
854 | |||
855 | static struct alpha_machine_vector *eb164_vecs[] __initdata = | ||
856 | { | ||
857 | &eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv, &rx164_mv | ||
858 | }; | ||
859 | |||
860 | static struct alpha_machine_vector *eb64p_vecs[] __initdata = | ||
861 | { | ||
862 | &eb64p_mv, | ||
863 | &cabriolet_mv, | ||
864 | &cabriolet_mv /* AlphaPCI64 */ | ||
865 | }; | ||
866 | |||
867 | static struct alpha_machine_vector *eb66_vecs[] __initdata = | ||
868 | { | ||
869 | &eb66_mv, | ||
870 | &eb66p_mv | ||
871 | }; | ||
872 | |||
873 | static struct alpha_machine_vector *marvel_vecs[] __initdata = | ||
874 | { | ||
875 | &marvel_ev7_mv, | ||
876 | }; | ||
877 | |||
878 | static struct alpha_machine_vector *titan_vecs[] __initdata = | ||
879 | { | ||
880 | &titan_mv, /* default */ | ||
881 | &privateer_mv, /* privateer */ | ||
882 | &titan_mv, /* falcon */ | ||
883 | &privateer_mv, /* granite */ | ||
884 | }; | ||
885 | |||
886 | static struct alpha_machine_vector *tsunami_vecs[] __initdata = | ||
887 | { | ||
888 | NULL, | ||
889 | &dp264_mv, /* dp264 */ | ||
890 | &dp264_mv, /* warhol */ | ||
891 | &dp264_mv, /* windjammer */ | ||
892 | &monet_mv, /* monet */ | ||
893 | &clipper_mv, /* clipper */ | ||
894 | &dp264_mv, /* goldrush */ | ||
895 | &webbrick_mv, /* webbrick */ | ||
896 | &dp264_mv, /* catamaran */ | ||
897 | NULL, /* brisbane? */ | ||
898 | NULL, /* melbourne? */ | ||
899 | NULL, /* flying clipper? */ | ||
900 | &shark_mv, /* shark */ | ||
901 | }; | ||
902 | |||
903 | /* ??? Do we need to distinguish between Rawhides? */ | ||
904 | |||
905 | struct alpha_machine_vector *vec; | ||
906 | |||
907 | /* Search the system tables first... */ | ||
908 | vec = NULL; | ||
909 | if (type < N(systype_vecs)) { | ||
910 | vec = systype_vecs[type]; | ||
911 | } else if ((type > ST_API_BIAS) && | ||
912 | (type - ST_API_BIAS) < N(api_vecs)) { | ||
913 | vec = api_vecs[type - ST_API_BIAS]; | ||
914 | } else if ((type > ST_UNOFFICIAL_BIAS) && | ||
915 | (type - ST_UNOFFICIAL_BIAS) < N(unofficial_vecs)) { | ||
916 | vec = unofficial_vecs[type - ST_UNOFFICIAL_BIAS]; | ||
917 | } | ||
918 | |||
919 | /* If we've not found one, try for a variation. */ | ||
920 | |||
921 | if (!vec) { | ||
922 | /* Member ID is a bit-field. */ | ||
923 | unsigned long member = (variation >> 10) & 0x3f; | ||
924 | |||
925 | cpu &= 0xffffffff; /* make it usable */ | ||
926 | |||
927 | switch (type) { | ||
928 | case ST_DEC_ALCOR: | ||
929 | if (member < N(alcor_indices)) | ||
930 | vec = alcor_vecs[alcor_indices[member]]; | ||
931 | break; | ||
932 | case ST_DEC_EB164: | ||
933 | if (member < N(eb164_indices)) | ||
934 | vec = eb164_vecs[eb164_indices[member]]; | ||
935 | /* PC164 may show as EB164 variation with EV56 CPU, | ||
936 | but, since no true EB164 had anything but EV5... */ | ||
937 | if (vec == &eb164_mv && cpu == EV56_CPU) | ||
938 | vec = &pc164_mv; | ||
939 | break; | ||
940 | case ST_DEC_EB64P: | ||
941 | if (member < N(eb64p_indices)) | ||
942 | vec = eb64p_vecs[eb64p_indices[member]]; | ||
943 | break; | ||
944 | case ST_DEC_EB66: | ||
945 | if (member < N(eb66_indices)) | ||
946 | vec = eb66_vecs[eb66_indices[member]]; | ||
947 | break; | ||
948 | case ST_DEC_MARVEL: | ||
949 | if (member < N(marvel_indices)) | ||
950 | vec = marvel_vecs[marvel_indices[member]]; | ||
951 | break; | ||
952 | case ST_DEC_TITAN: | ||
953 | vec = titan_vecs[0]; /* default */ | ||
954 | if (member < N(titan_indices)) | ||
955 | vec = titan_vecs[titan_indices[member]]; | ||
956 | break; | ||
957 | case ST_DEC_TSUNAMI: | ||
958 | if (member < N(tsunami_indices)) | ||
959 | vec = tsunami_vecs[tsunami_indices[member]]; | ||
960 | break; | ||
961 | case ST_DEC_1000: | ||
962 | if (cpu == EV5_CPU || cpu == EV56_CPU) | ||
963 | vec = &mikasa_primo_mv; | ||
964 | else | ||
965 | vec = &mikasa_mv; | ||
966 | break; | ||
967 | case ST_DEC_NORITAKE: | ||
968 | if (cpu == EV5_CPU || cpu == EV56_CPU) | ||
969 | vec = &noritake_primo_mv; | ||
970 | else | ||
971 | vec = &noritake_mv; | ||
972 | break; | ||
973 | case ST_DEC_2100_A500: | ||
974 | if (cpu == EV5_CPU || cpu == EV56_CPU) | ||
975 | vec = &sable_gamma_mv; | ||
976 | else | ||
977 | vec = &sable_mv; | ||
978 | break; | ||
979 | } | ||
980 | } | ||
981 | return vec; | ||
982 | } | ||
983 | |||
984 | static struct alpha_machine_vector * __init | ||
985 | get_sysvec_byname(const char *name) | ||
986 | { | ||
987 | static struct alpha_machine_vector *all_vecs[] __initdata = | ||
988 | { | ||
989 | &alcor_mv, | ||
990 | &alphabook1_mv, | ||
991 | &avanti_mv, | ||
992 | &cabriolet_mv, | ||
993 | &clipper_mv, | ||
994 | &dp264_mv, | ||
995 | &eb164_mv, | ||
996 | &eb64p_mv, | ||
997 | &eb66_mv, | ||
998 | &eb66p_mv, | ||
999 | &eiger_mv, | ||
1000 | &jensen_mv, | ||
1001 | &lx164_mv, | ||
1002 | &lynx_mv, | ||
1003 | &miata_mv, | ||
1004 | &mikasa_mv, | ||
1005 | &mikasa_primo_mv, | ||
1006 | &monet_mv, | ||
1007 | &nautilus_mv, | ||
1008 | &noname_mv, | ||
1009 | &noritake_mv, | ||
1010 | &noritake_primo_mv, | ||
1011 | &p2k_mv, | ||
1012 | &pc164_mv, | ||
1013 | &privateer_mv, | ||
1014 | &rawhide_mv, | ||
1015 | &ruffian_mv, | ||
1016 | &rx164_mv, | ||
1017 | &sable_mv, | ||
1018 | &sable_gamma_mv, | ||
1019 | &shark_mv, | ||
1020 | &sx164_mv, | ||
1021 | &takara_mv, | ||
1022 | &webbrick_mv, | ||
1023 | &wildfire_mv, | ||
1024 | &xl_mv, | ||
1025 | &xlt_mv | ||
1026 | }; | ||
1027 | |||
1028 | size_t i; | ||
1029 | |||
1030 | for (i = 0; i < N(all_vecs); ++i) { | ||
1031 | struct alpha_machine_vector *mv = all_vecs[i]; | ||
1032 | if (strcasecmp(mv->vector_name, name) == 0) | ||
1033 | return mv; | ||
1034 | } | ||
1035 | return NULL; | ||
1036 | } | ||
1037 | |||
1038 | static void | ||
1039 | get_sysnames(unsigned long type, unsigned long variation, unsigned long cpu, | ||
1040 | char **type_name, char **variation_name) | ||
1041 | { | ||
1042 | unsigned long member; | ||
1043 | |||
1044 | /* If not in the tables, make it UNKNOWN, | ||
1045 | else set type name to family */ | ||
1046 | if (type < N(systype_names)) { | ||
1047 | *type_name = systype_names[type]; | ||
1048 | } else if ((type > ST_API_BIAS) && | ||
1049 | (type - ST_API_BIAS) < N(api_names)) { | ||
1050 | *type_name = api_names[type - ST_API_BIAS]; | ||
1051 | } else if ((type > ST_UNOFFICIAL_BIAS) && | ||
1052 | (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) { | ||
1053 | *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS]; | ||
1054 | } else { | ||
1055 | *type_name = sys_unknown; | ||
1056 | *variation_name = sys_unknown; | ||
1057 | return; | ||
1058 | } | ||
1059 | |||
1060 | /* Set variation to "0"; if variation is zero, done. */ | ||
1061 | *variation_name = systype_names[0]; | ||
1062 | if (variation == 0) { | ||
1063 | return; | ||
1064 | } | ||
1065 | |||
1066 | member = (variation >> 10) & 0x3f; /* member ID is a bit-field */ | ||
1067 | |||
1068 | cpu &= 0xffffffff; /* make it usable */ | ||
1069 | |||
1070 | switch (type) { /* select by family */ | ||
1071 | default: /* default to variation "0" for now */ | ||
1072 | break; | ||
1073 | case ST_DEC_EB164: | ||
1074 | if (member < N(eb164_indices)) | ||
1075 | *variation_name = eb164_names[eb164_indices[member]]; | ||
1076 | /* PC164 may show as EB164 variation, but with EV56 CPU, | ||
1077 | so, since no true EB164 had anything but EV5... */ | ||
1078 | if (eb164_indices[member] == 0 && cpu == EV56_CPU) | ||
1079 | *variation_name = eb164_names[1]; /* make it PC164 */ | ||
1080 | break; | ||
1081 | case ST_DEC_ALCOR: | ||
1082 | if (member < N(alcor_indices)) | ||
1083 | *variation_name = alcor_names[alcor_indices[member]]; | ||
1084 | break; | ||
1085 | case ST_DEC_EB64P: | ||
1086 | if (member < N(eb64p_indices)) | ||
1087 | *variation_name = eb64p_names[eb64p_indices[member]]; | ||
1088 | break; | ||
1089 | case ST_DEC_EB66: | ||
1090 | if (member < N(eb66_indices)) | ||
1091 | *variation_name = eb66_names[eb66_indices[member]]; | ||
1092 | break; | ||
1093 | case ST_DEC_MARVEL: | ||
1094 | if (member < N(marvel_indices)) | ||
1095 | *variation_name = marvel_names[marvel_indices[member]]; | ||
1096 | break; | ||
1097 | case ST_DEC_RAWHIDE: | ||
1098 | if (member < N(rawhide_indices)) | ||
1099 | *variation_name = rawhide_names[rawhide_indices[member]]; | ||
1100 | break; | ||
1101 | case ST_DEC_TITAN: | ||
1102 | *variation_name = titan_names[0]; /* default */ | ||
1103 | if (member < N(titan_indices)) | ||
1104 | *variation_name = titan_names[titan_indices[member]]; | ||
1105 | break; | ||
1106 | case ST_DEC_TSUNAMI: | ||
1107 | if (member < N(tsunami_indices)) | ||
1108 | *variation_name = tsunami_names[tsunami_indices[member]]; | ||
1109 | break; | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | /* | ||
1114 | * A change was made to the HWRPB via an ECO and the following code | ||
1115 | * tracks a part of the ECO. In HWRPB versions less than 5, the ECO | ||
1116 | * was not implemented in the console firmware. If it's revision 5 or | ||
1117 | * greater we can get the name of the platform as an ASCII string from | ||
1118 | * the HWRPB. That's what this function does. It checks the revision | ||
1119 | * level and if the string is in the HWRPB it returns the address of | ||
1120 | * the string--a pointer to the name of the platform. | ||
1121 | * | ||
1122 | * Returns: | ||
1123 | * - Pointer to a ASCII string if it's in the HWRPB | ||
1124 | * - Pointer to a blank string if the data is not in the HWRPB. | ||
1125 | */ | ||
1126 | |||
1127 | static char * | ||
1128 | platform_string(void) | ||
1129 | { | ||
1130 | struct dsr_struct *dsr; | ||
1131 | static char unk_system_string[] = "N/A"; | ||
1132 | |||
1133 | /* Go to the console for the string pointer. | ||
1134 | * If the rpb_vers is not 5 or greater the rpb | ||
1135 | * is old and does not have this data in it. | ||
1136 | */ | ||
1137 | if (hwrpb->revision < 5) | ||
1138 | return (unk_system_string); | ||
1139 | else { | ||
1140 | /* The Dynamic System Recognition struct | ||
1141 | * has the system platform name starting | ||
1142 | * after the character count of the string. | ||
1143 | */ | ||
1144 | dsr = ((struct dsr_struct *) | ||
1145 | ((char *)hwrpb + hwrpb->dsr_offset)); | ||
1146 | return ((char *)dsr + (dsr->sysname_off + | ||
1147 | sizeof(long))); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | static int | ||
1152 | get_nr_processors(struct percpu_struct *cpubase, unsigned long num) | ||
1153 | { | ||
1154 | struct percpu_struct *cpu; | ||
1155 | unsigned long i; | ||
1156 | int count = 0; | ||
1157 | |||
1158 | for (i = 0; i < num; i++) { | ||
1159 | cpu = (struct percpu_struct *) | ||
1160 | ((char *)cpubase + i*hwrpb->processor_size); | ||
1161 | if ((cpu->flags & 0x1cc) == 0x1cc) | ||
1162 | count++; | ||
1163 | } | ||
1164 | return count; | ||
1165 | } | ||
1166 | |||
1167 | static void | ||
1168 | show_cache_size (struct seq_file *f, const char *which, int shape) | ||
1169 | { | ||
1170 | if (shape == -1) | ||
1171 | seq_printf (f, "%s\t\t: n/a\n", which); | ||
1172 | else if (shape == 0) | ||
1173 | seq_printf (f, "%s\t\t: unknown\n", which); | ||
1174 | else | ||
1175 | seq_printf (f, "%s\t\t: %dK, %d-way, %db line\n", | ||
1176 | which, shape >> 10, shape & 15, | ||
1177 | 1 << ((shape >> 4) & 15)); | ||
1178 | } | ||
1179 | |||
1180 | static int | ||
1181 | show_cpuinfo(struct seq_file *f, void *slot) | ||
1182 | { | ||
1183 | extern struct unaligned_stat { | ||
1184 | unsigned long count, va, pc; | ||
1185 | } unaligned[2]; | ||
1186 | |||
1187 | static char cpu_names[][8] = { | ||
1188 | "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", | ||
1189 | "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL", | ||
1190 | "EV68CX", "EV7", "EV79", "EV69" | ||
1191 | }; | ||
1192 | |||
1193 | struct percpu_struct *cpu = slot; | ||
1194 | unsigned int cpu_index; | ||
1195 | char *cpu_name; | ||
1196 | char *systype_name; | ||
1197 | char *sysvariation_name; | ||
1198 | int nr_processors; | ||
1199 | |||
1200 | cpu_index = (unsigned) (cpu->type - 1); | ||
1201 | cpu_name = "Unknown"; | ||
1202 | if (cpu_index < N(cpu_names)) | ||
1203 | cpu_name = cpu_names[cpu_index]; | ||
1204 | |||
1205 | get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, | ||
1206 | cpu->type, &systype_name, &sysvariation_name); | ||
1207 | |||
1208 | nr_processors = get_nr_processors(cpu, hwrpb->nr_processors); | ||
1209 | |||
1210 | seq_printf(f, "cpu\t\t\t: Alpha\n" | ||
1211 | "cpu model\t\t: %s\n" | ||
1212 | "cpu variation\t\t: %ld\n" | ||
1213 | "cpu revision\t\t: %ld\n" | ||
1214 | "cpu serial number\t: %s\n" | ||
1215 | "system type\t\t: %s\n" | ||
1216 | "system variation\t: %s\n" | ||
1217 | "system revision\t\t: %ld\n" | ||
1218 | "system serial number\t: %s\n" | ||
1219 | "cycle frequency [Hz]\t: %lu %s\n" | ||
1220 | "timer frequency [Hz]\t: %lu.%02lu\n" | ||
1221 | "page size [bytes]\t: %ld\n" | ||
1222 | "phys. address bits\t: %ld\n" | ||
1223 | "max. addr. space #\t: %ld\n" | ||
1224 | "BogoMIPS\t\t: %lu.%02lu\n" | ||
1225 | "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" | ||
1226 | "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" | ||
1227 | "platform string\t\t: %s\n" | ||
1228 | "cpus detected\t\t: %d\n", | ||
1229 | cpu_name, cpu->variation, cpu->revision, | ||
1230 | (char*)cpu->serial_no, | ||
1231 | systype_name, sysvariation_name, hwrpb->sys_revision, | ||
1232 | (char*)hwrpb->ssn, | ||
1233 | est_cycle_freq ? : hwrpb->cycle_freq, | ||
1234 | est_cycle_freq ? "est." : "", | ||
1235 | hwrpb->intr_freq / 4096, | ||
1236 | (100 * hwrpb->intr_freq / 4096) % 100, | ||
1237 | hwrpb->pagesize, | ||
1238 | hwrpb->pa_bits, | ||
1239 | hwrpb->max_asn, | ||
1240 | loops_per_jiffy / (500000/HZ), | ||
1241 | (loops_per_jiffy / (5000/HZ)) % 100, | ||
1242 | unaligned[0].count, unaligned[0].pc, unaligned[0].va, | ||
1243 | unaligned[1].count, unaligned[1].pc, unaligned[1].va, | ||
1244 | platform_string(), nr_processors); | ||
1245 | |||
1246 | #ifdef CONFIG_SMP | ||
1247 | seq_printf(f, "cpus active\t\t: %d\n" | ||
1248 | "cpu active mask\t\t: %016lx\n", | ||
1249 | num_online_cpus(), cpus_addr(cpu_possible_map)[0]); | ||
1250 | #endif | ||
1251 | |||
1252 | show_cache_size (f, "L1 Icache", alpha_l1i_cacheshape); | ||
1253 | show_cache_size (f, "L1 Dcache", alpha_l1d_cacheshape); | ||
1254 | show_cache_size (f, "L2 cache", alpha_l2_cacheshape); | ||
1255 | show_cache_size (f, "L3 cache", alpha_l3_cacheshape); | ||
1256 | |||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | static int __init | ||
1261 | read_mem_block(int *addr, int stride, int size) | ||
1262 | { | ||
1263 | long nloads = size / stride, cnt, tmp; | ||
1264 | |||
1265 | __asm__ __volatile__( | ||
1266 | " rpcc %0\n" | ||
1267 | "1: ldl %3,0(%2)\n" | ||
1268 | " subq %1,1,%1\n" | ||
1269 | /* Next two XORs introduce an explicit data dependency between | ||
1270 | consecutive loads in the loop, which will give us true load | ||
1271 | latency. */ | ||
1272 | " xor %3,%2,%2\n" | ||
1273 | " xor %3,%2,%2\n" | ||
1274 | " addq %2,%4,%2\n" | ||
1275 | " bne %1,1b\n" | ||
1276 | " rpcc %3\n" | ||
1277 | " subl %3,%0,%0\n" | ||
1278 | : "=&r" (cnt), "=&r" (nloads), "=&r" (addr), "=&r" (tmp) | ||
1279 | : "r" (stride), "1" (nloads), "2" (addr)); | ||
1280 | |||
1281 | return cnt / (size / stride); | ||
1282 | } | ||
1283 | |||
1284 | #define CSHAPE(totalsize, linesize, assoc) \ | ||
1285 | ((totalsize & ~0xff) | (linesize << 4) | assoc) | ||
1286 | |||
1287 | /* ??? EV5 supports up to 64M, but did the systems with more than | ||
1288 | 16M of BCACHE ever exist? */ | ||
1289 | #define MAX_BCACHE_SIZE 16*1024*1024 | ||
1290 | |||
1291 | /* Note that the offchip caches are direct mapped on all Alphas. */ | ||
1292 | static int __init | ||
1293 | external_cache_probe(int minsize, int width) | ||
1294 | { | ||
1295 | int cycles, prev_cycles = 1000000; | ||
1296 | int stride = 1 << width; | ||
1297 | long size = minsize, maxsize = MAX_BCACHE_SIZE * 2; | ||
1298 | |||
1299 | if (maxsize > (max_low_pfn + 1) << PAGE_SHIFT) | ||
1300 | maxsize = 1 << (floor_log2(max_low_pfn + 1) + PAGE_SHIFT); | ||
1301 | |||
1302 | /* Get the first block cached. */ | ||
1303 | read_mem_block(__va(0), stride, size); | ||
1304 | |||
1305 | while (size < maxsize) { | ||
1306 | /* Get an average load latency in cycles. */ | ||
1307 | cycles = read_mem_block(__va(0), stride, size); | ||
1308 | if (cycles > prev_cycles * 2) { | ||
1309 | /* Fine, we exceed the cache. */ | ||
1310 | printk("%ldK Bcache detected; load hit latency %d " | ||
1311 | "cycles, load miss latency %d cycles\n", | ||
1312 | size >> 11, prev_cycles, cycles); | ||
1313 | return CSHAPE(size >> 1, width, 1); | ||
1314 | } | ||
1315 | /* Try to get the next block cached. */ | ||
1316 | read_mem_block(__va(size), stride, size); | ||
1317 | prev_cycles = cycles; | ||
1318 | size <<= 1; | ||
1319 | } | ||
1320 | return -1; /* No BCACHE found. */ | ||
1321 | } | ||
1322 | |||
1323 | static void __init | ||
1324 | determine_cpu_caches (unsigned int cpu_type) | ||
1325 | { | ||
1326 | int L1I, L1D, L2, L3; | ||
1327 | |||
1328 | switch (cpu_type) { | ||
1329 | case EV4_CPU: | ||
1330 | case EV45_CPU: | ||
1331 | { | ||
1332 | if (cpu_type == EV4_CPU) | ||
1333 | L1I = CSHAPE(8*1024, 5, 1); | ||
1334 | else | ||
1335 | L1I = CSHAPE(16*1024, 5, 1); | ||
1336 | L1D = L1I; | ||
1337 | L3 = -1; | ||
1338 | |||
1339 | /* BIU_CTL is a write-only Abox register. PALcode has a | ||
1340 | shadow copy, and may be available from some versions | ||
1341 | of the CSERVE PALcall. If we can get it, then | ||
1342 | |||
1343 | unsigned long biu_ctl, size; | ||
1344 | size = 128*1024 * (1 << ((biu_ctl >> 28) & 7)); | ||
1345 | L2 = CSHAPE (size, 5, 1); | ||
1346 | |||
1347 | Unfortunately, we can't rely on that. | ||
1348 | */ | ||
1349 | L2 = external_cache_probe(128*1024, 5); | ||
1350 | break; | ||
1351 | } | ||
1352 | |||
1353 | case LCA4_CPU: | ||
1354 | { | ||
1355 | unsigned long car, size; | ||
1356 | |||
1357 | L1I = L1D = CSHAPE(8*1024, 5, 1); | ||
1358 | L3 = -1; | ||
1359 | |||
1360 | car = *(vuip) phys_to_virt (0x120000078UL); | ||
1361 | size = 64*1024 * (1 << ((car >> 5) & 7)); | ||
1362 | /* No typo -- 8 byte cacheline size. Whodathunk. */ | ||
1363 | L2 = (car & 1 ? CSHAPE (size, 3, 1) : -1); | ||
1364 | break; | ||
1365 | } | ||
1366 | |||
1367 | case EV5_CPU: | ||
1368 | case EV56_CPU: | ||
1369 | { | ||
1370 | unsigned long sc_ctl, width; | ||
1371 | |||
1372 | L1I = L1D = CSHAPE(8*1024, 5, 1); | ||
1373 | |||
1374 | /* Check the line size of the Scache. */ | ||
1375 | sc_ctl = *(vulp) phys_to_virt (0xfffff000a8UL); | ||
1376 | width = sc_ctl & 0x1000 ? 6 : 5; | ||
1377 | L2 = CSHAPE (96*1024, width, 3); | ||
1378 | |||
1379 | /* BC_CONTROL and BC_CONFIG are write-only IPRs. PALcode | ||
1380 | has a shadow copy, and may be available from some versions | ||
1381 | of the CSERVE PALcall. If we can get it, then | ||
1382 | |||
1383 | unsigned long bc_control, bc_config, size; | ||
1384 | size = 1024*1024 * (1 << ((bc_config & 7) - 1)); | ||
1385 | L3 = (bc_control & 1 ? CSHAPE (size, width, 1) : -1); | ||
1386 | |||
1387 | Unfortunately, we can't rely on that. | ||
1388 | */ | ||
1389 | L3 = external_cache_probe(1024*1024, width); | ||
1390 | break; | ||
1391 | } | ||
1392 | |||
1393 | case PCA56_CPU: | ||
1394 | case PCA57_CPU: | ||
1395 | { | ||
1396 | unsigned long cbox_config, size; | ||
1397 | |||
1398 | if (cpu_type == PCA56_CPU) { | ||
1399 | L1I = CSHAPE(16*1024, 6, 1); | ||
1400 | L1D = CSHAPE(8*1024, 5, 1); | ||
1401 | } else { | ||
1402 | L1I = CSHAPE(32*1024, 6, 2); | ||
1403 | L1D = CSHAPE(16*1024, 5, 1); | ||
1404 | } | ||
1405 | L3 = -1; | ||
1406 | |||
1407 | cbox_config = *(vulp) phys_to_virt (0xfffff00008UL); | ||
1408 | size = 512*1024 * (1 << ((cbox_config >> 12) & 3)); | ||
1409 | |||
1410 | #if 0 | ||
1411 | L2 = ((cbox_config >> 31) & 1 ? CSHAPE (size, 6, 1) : -1); | ||
1412 | #else | ||
1413 | L2 = external_cache_probe(512*1024, 6); | ||
1414 | #endif | ||
1415 | break; | ||
1416 | } | ||
1417 | |||
1418 | case EV6_CPU: | ||
1419 | case EV67_CPU: | ||
1420 | case EV68CB_CPU: | ||
1421 | case EV68AL_CPU: | ||
1422 | case EV68CX_CPU: | ||
1423 | case EV69_CPU: | ||
1424 | L1I = L1D = CSHAPE(64*1024, 6, 2); | ||
1425 | L2 = external_cache_probe(1024*1024, 6); | ||
1426 | L3 = -1; | ||
1427 | break; | ||
1428 | |||
1429 | case EV7_CPU: | ||
1430 | case EV79_CPU: | ||
1431 | L1I = L1D = CSHAPE(64*1024, 6, 2); | ||
1432 | L2 = CSHAPE(7*1024*1024/4, 6, 7); | ||
1433 | L3 = -1; | ||
1434 | break; | ||
1435 | |||
1436 | default: | ||
1437 | /* Nothing known about this cpu type. */ | ||
1438 | L1I = L1D = L2 = L3 = 0; | ||
1439 | break; | ||
1440 | } | ||
1441 | |||
1442 | alpha_l1i_cacheshape = L1I; | ||
1443 | alpha_l1d_cacheshape = L1D; | ||
1444 | alpha_l2_cacheshape = L2; | ||
1445 | alpha_l3_cacheshape = L3; | ||
1446 | } | ||
1447 | |||
1448 | /* | ||
1449 | * We show only CPU #0 info. | ||
1450 | */ | ||
1451 | static void * | ||
1452 | c_start(struct seq_file *f, loff_t *pos) | ||
1453 | { | ||
1454 | return *pos ? NULL : (char *)hwrpb + hwrpb->processor_offset; | ||
1455 | } | ||
1456 | |||
1457 | static void * | ||
1458 | c_next(struct seq_file *f, void *v, loff_t *pos) | ||
1459 | { | ||
1460 | return NULL; | ||
1461 | } | ||
1462 | |||
1463 | static void | ||
1464 | c_stop(struct seq_file *f, void *v) | ||
1465 | { | ||
1466 | } | ||
1467 | |||
1468 | struct seq_operations cpuinfo_op = { | ||
1469 | .start = c_start, | ||
1470 | .next = c_next, | ||
1471 | .stop = c_stop, | ||
1472 | .show = show_cpuinfo, | ||
1473 | }; | ||
1474 | |||
1475 | |||
1476 | static int | ||
1477 | alpha_panic_event(struct notifier_block *this, unsigned long event, void *ptr) | ||
1478 | { | ||
1479 | #if 1 | ||
1480 | /* FIXME FIXME FIXME */ | ||
1481 | /* If we are using SRM and serial console, just hard halt here. */ | ||
1482 | if (alpha_using_srm && srmcons_output) | ||
1483 | __halt(); | ||
1484 | #endif | ||
1485 | return NOTIFY_DONE; | ||
1486 | } | ||