aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/setup.c')
-rw-r--r--arch/arm/kernel/setup.c875
1 files changed, 875 insertions, 0 deletions
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
new file mode 100644
index 000000000000..c2a7da3ac0f1
--- /dev/null
+++ b/arch/arm/kernel/setup.c
@@ -0,0 +1,875 @@
1/*
2 * linux/arch/arm/kernel/setup.c
3 *
4 * Copyright (C) 1995-2001 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/config.h>
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/stddef.h>
14#include <linux/ioport.h>
15#include <linux/delay.h>
16#include <linux/utsname.h>
17#include <linux/initrd.h>
18#include <linux/console.h>
19#include <linux/bootmem.h>
20#include <linux/seq_file.h>
21#include <linux/tty.h>
22#include <linux/init.h>
23#include <linux/root_dev.h>
24#include <linux/cpu.h>
25#include <linux/interrupt.h>
26
27#include <asm/cpu.h>
28#include <asm/elf.h>
29#include <asm/hardware.h>
30#include <asm/io.h>
31#include <asm/procinfo.h>
32#include <asm/setup.h>
33#include <asm/mach-types.h>
34#include <asm/cacheflush.h>
35#include <asm/tlbflush.h>
36
37#include <asm/mach/arch.h>
38#include <asm/mach/irq.h>
39#include <asm/mach/time.h>
40
41#ifndef MEM_SIZE
42#define MEM_SIZE (16*1024*1024)
43#endif
44
45#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
46char fpe_type[8];
47
48static int __init fpe_setup(char *line)
49{
50 memcpy(fpe_type, line, 8);
51 return 1;
52}
53
54__setup("fpe=", fpe_setup);
55#endif
56
57extern unsigned int mem_fclk_21285;
58extern void paging_init(struct meminfo *, struct machine_desc *desc);
59extern void convert_to_tag_list(struct tag *tags);
60extern void squash_mem_tags(struct tag *tag);
61extern void reboot_setup(char *str);
62extern int root_mountflags;
63extern void _stext, _text, _etext, __data_start, _edata, _end;
64
65unsigned int processor_id;
66unsigned int __machine_arch_type;
67EXPORT_SYMBOL(__machine_arch_type);
68
69unsigned int system_rev;
70EXPORT_SYMBOL(system_rev);
71
72unsigned int system_serial_low;
73EXPORT_SYMBOL(system_serial_low);
74
75unsigned int system_serial_high;
76EXPORT_SYMBOL(system_serial_high);
77
78unsigned int elf_hwcap;
79EXPORT_SYMBOL(elf_hwcap);
80
81
82#ifdef MULTI_CPU
83struct processor processor;
84#endif
85#ifdef MULTI_TLB
86struct cpu_tlb_fns cpu_tlb;
87#endif
88#ifdef MULTI_USER
89struct cpu_user_fns cpu_user;
90#endif
91#ifdef MULTI_CACHE
92struct cpu_cache_fns cpu_cache;
93#endif
94
95char elf_platform[ELF_PLATFORM_SIZE];
96EXPORT_SYMBOL(elf_platform);
97
98unsigned long phys_initrd_start __initdata = 0;
99unsigned long phys_initrd_size __initdata = 0;
100
101static struct meminfo meminfo __initdata = { 0, };
102static const char *cpu_name;
103static const char *machine_name;
104static char command_line[COMMAND_LINE_SIZE];
105
106static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
107static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
108#define ENDIANNESS ((char)endian_test.l)
109
110DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
111
112/*
113 * Standard memory resources
114 */
115static struct resource mem_res[] = {
116 { "Video RAM", 0, 0, IORESOURCE_MEM },
117 { "Kernel text", 0, 0, IORESOURCE_MEM },
118 { "Kernel data", 0, 0, IORESOURCE_MEM }
119};
120
121#define video_ram mem_res[0]
122#define kernel_code mem_res[1]
123#define kernel_data mem_res[2]
124
125static struct resource io_res[] = {
126 { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
127 { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
128 { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
129};
130
131#define lp0 io_res[0]
132#define lp1 io_res[1]
133#define lp2 io_res[2]
134
135static const char *cache_types[16] = {
136 "write-through",
137 "write-back",
138 "write-back",
139 "undefined 3",
140 "undefined 4",
141 "undefined 5",
142 "write-back",
143 "write-back",
144 "undefined 8",
145 "undefined 9",
146 "undefined 10",
147 "undefined 11",
148 "undefined 12",
149 "undefined 13",
150 "write-back",
151 "undefined 15",
152};
153
154static const char *cache_clean[16] = {
155 "not required",
156 "read-block",
157 "cp15 c7 ops",
158 "undefined 3",
159 "undefined 4",
160 "undefined 5",
161 "cp15 c7 ops",
162 "cp15 c7 ops",
163 "undefined 8",
164 "undefined 9",
165 "undefined 10",
166 "undefined 11",
167 "undefined 12",
168 "undefined 13",
169 "cp15 c7 ops",
170 "undefined 15",
171};
172
173static const char *cache_lockdown[16] = {
174 "not supported",
175 "not supported",
176 "not supported",
177 "undefined 3",
178 "undefined 4",
179 "undefined 5",
180 "format A",
181 "format B",
182 "undefined 8",
183 "undefined 9",
184 "undefined 10",
185 "undefined 11",
186 "undefined 12",
187 "undefined 13",
188 "format C",
189 "undefined 15",
190};
191
192static const char *proc_arch[] = {
193 "undefined/unknown",
194 "3",
195 "4",
196 "4T",
197 "5",
198 "5T",
199 "5TE",
200 "5TEJ",
201 "6TEJ",
202 "?(10)",
203 "?(11)",
204 "?(12)",
205 "?(13)",
206 "?(14)",
207 "?(15)",
208 "?(16)",
209 "?(17)",
210};
211
212#define CACHE_TYPE(x) (((x) >> 25) & 15)
213#define CACHE_S(x) ((x) & (1 << 24))
214#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
215#define CACHE_ISIZE(x) ((x) & 4095)
216
217#define CACHE_SIZE(y) (((y) >> 6) & 7)
218#define CACHE_ASSOC(y) (((y) >> 3) & 7)
219#define CACHE_M(y) ((y) & (1 << 2))
220#define CACHE_LINE(y) ((y) & 3)
221
222static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
223{
224 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
225
226 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
227 cpu, prefix,
228 mult << (8 + CACHE_SIZE(cache)),
229 (mult << CACHE_ASSOC(cache)) >> 1,
230 8 << CACHE_LINE(cache),
231 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
232 CACHE_LINE(cache)));
233}
234
235static void __init dump_cpu_info(int cpu)
236{
237 unsigned int info = read_cpuid(CPUID_CACHETYPE);
238
239 if (info != processor_id) {
240 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
241 cache_types[CACHE_TYPE(info)]);
242 if (CACHE_S(info)) {
243 dump_cache("I cache", cpu, CACHE_ISIZE(info));
244 dump_cache("D cache", cpu, CACHE_DSIZE(info));
245 } else {
246 dump_cache("cache", cpu, CACHE_ISIZE(info));
247 }
248 }
249}
250
251int cpu_architecture(void)
252{
253 int cpu_arch;
254
255 if ((processor_id & 0x0000f000) == 0) {
256 cpu_arch = CPU_ARCH_UNKNOWN;
257 } else if ((processor_id & 0x0000f000) == 0x00007000) {
258 cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
259 } else {
260 cpu_arch = (processor_id >> 16) & 7;
261 if (cpu_arch)
262 cpu_arch += CPU_ARCH_ARMv3;
263 }
264
265 return cpu_arch;
266}
267
268/*
269 * These functions re-use the assembly code in head.S, which
270 * already provide the required functionality.
271 */
272extern struct proc_info_list *lookup_processor_type(void);
273extern struct machine_desc *lookup_machine_type(unsigned int);
274
275static void __init setup_processor(void)
276{
277 struct proc_info_list *list;
278
279 /*
280 * locate processor in the list of supported processor
281 * types. The linker builds this table for us from the
282 * entries in arch/arm/mm/proc-*.S
283 */
284 list = lookup_processor_type();
285 if (!list) {
286 printk("CPU configuration botched (ID %08x), unable "
287 "to continue.\n", processor_id);
288 while (1);
289 }
290
291 cpu_name = list->cpu_name;
292
293#ifdef MULTI_CPU
294 processor = *list->proc;
295#endif
296#ifdef MULTI_TLB
297 cpu_tlb = *list->tlb;
298#endif
299#ifdef MULTI_USER
300 cpu_user = *list->user;
301#endif
302#ifdef MULTI_CACHE
303 cpu_cache = *list->cache;
304#endif
305
306 printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
307 cpu_name, processor_id, (int)processor_id & 15,
308 proc_arch[cpu_architecture()]);
309
310 dump_cpu_info(smp_processor_id());
311
312 sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
313 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
314 elf_hwcap = list->elf_hwcap;
315
316 cpu_proc_init();
317}
318
319static struct machine_desc * __init setup_machine(unsigned int nr)
320{
321 struct machine_desc *list;
322
323 /*
324 * locate machine in the list of supported machines.
325 */
326 list = lookup_machine_type(nr);
327 if (!list) {
328 printk("Machine configuration botched (nr %d), unable "
329 "to continue.\n", nr);
330 while (1);
331 }
332
333 printk("Machine: %s\n", list->name);
334
335 return list;
336}
337
338static void __init early_initrd(char **p)
339{
340 unsigned long start, size;
341
342 start = memparse(*p, p);
343 if (**p == ',') {
344 size = memparse((*p) + 1, p);
345
346 phys_initrd_start = start;
347 phys_initrd_size = size;
348 }
349}
350__early_param("initrd=", early_initrd);
351
352/*
353 * Pick out the memory size. We look for mem=size@start,
354 * where start and size are "size[KkMm]"
355 */
356static void __init early_mem(char **p)
357{
358 static int usermem __initdata = 0;
359 unsigned long size, start;
360
361 /*
362 * If the user specifies memory size, we
363 * blow away any automatically generated
364 * size.
365 */
366 if (usermem == 0) {
367 usermem = 1;
368 meminfo.nr_banks = 0;
369 }
370
371 start = PHYS_OFFSET;
372 size = memparse(*p, p);
373 if (**p == '@')
374 start = memparse(*p + 1, p);
375
376 meminfo.bank[meminfo.nr_banks].start = start;
377 meminfo.bank[meminfo.nr_banks].size = size;
378 meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start);
379 meminfo.nr_banks += 1;
380}
381__early_param("mem=", early_mem);
382
383/*
384 * Initial parsing of the command line.
385 */
386static void __init parse_cmdline(char **cmdline_p, char *from)
387{
388 char c = ' ', *to = command_line;
389 int len = 0;
390
391 for (;;) {
392 if (c == ' ') {
393 extern struct early_params __early_begin, __early_end;
394 struct early_params *p;
395
396 for (p = &__early_begin; p < &__early_end; p++) {
397 int len = strlen(p->arg);
398
399 if (memcmp(from, p->arg, len) == 0) {
400 if (to != command_line)
401 to -= 1;
402 from += len;
403 p->fn(&from);
404
405 while (*from != ' ' && *from != '\0')
406 from++;
407 break;
408 }
409 }
410 }
411 c = *from++;
412 if (!c)
413 break;
414 if (COMMAND_LINE_SIZE <= ++len)
415 break;
416 *to++ = c;
417 }
418 *to = '\0';
419 *cmdline_p = command_line;
420}
421
422static void __init
423setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
424{
425#ifdef CONFIG_BLK_DEV_RAM
426 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
427
428 rd_image_start = image_start;
429 rd_prompt = prompt;
430 rd_doload = doload;
431
432 if (rd_sz)
433 rd_size = rd_sz;
434#endif
435}
436
437static void __init
438request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
439{
440 struct resource *res;
441 int i;
442
443 kernel_code.start = virt_to_phys(&_text);
444 kernel_code.end = virt_to_phys(&_etext - 1);
445 kernel_data.start = virt_to_phys(&__data_start);
446 kernel_data.end = virt_to_phys(&_end - 1);
447
448 for (i = 0; i < mi->nr_banks; i++) {
449 unsigned long virt_start, virt_end;
450
451 if (mi->bank[i].size == 0)
452 continue;
453
454 virt_start = __phys_to_virt(mi->bank[i].start);
455 virt_end = virt_start + mi->bank[i].size - 1;
456
457 res = alloc_bootmem_low(sizeof(*res));
458 res->name = "System RAM";
459 res->start = __virt_to_phys(virt_start);
460 res->end = __virt_to_phys(virt_end);
461 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
462
463 request_resource(&iomem_resource, res);
464
465 if (kernel_code.start >= res->start &&
466 kernel_code.end <= res->end)
467 request_resource(res, &kernel_code);
468 if (kernel_data.start >= res->start &&
469 kernel_data.end <= res->end)
470 request_resource(res, &kernel_data);
471 }
472
473 if (mdesc->video_start) {
474 video_ram.start = mdesc->video_start;
475 video_ram.end = mdesc->video_end;
476 request_resource(&iomem_resource, &video_ram);
477 }
478
479 /*
480 * Some machines don't have the possibility of ever
481 * possessing lp0, lp1 or lp2
482 */
483 if (mdesc->reserve_lp0)
484 request_resource(&ioport_resource, &lp0);
485 if (mdesc->reserve_lp1)
486 request_resource(&ioport_resource, &lp1);
487 if (mdesc->reserve_lp2)
488 request_resource(&ioport_resource, &lp2);
489}
490
491/*
492 * Tag parsing.
493 *
494 * This is the new way of passing data to the kernel at boot time. Rather
495 * than passing a fixed inflexible structure to the kernel, we pass a list
496 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
497 * tag for the list to be recognised (to distinguish the tagged list from
498 * a param_struct). The list is terminated with a zero-length tag (this tag
499 * is not parsed in any way).
500 */
501static int __init parse_tag_core(const struct tag *tag)
502{
503 if (tag->hdr.size > 2) {
504 if ((tag->u.core.flags & 1) == 0)
505 root_mountflags &= ~MS_RDONLY;
506 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
507 }
508 return 0;
509}
510
511__tagtable(ATAG_CORE, parse_tag_core);
512
513static int __init parse_tag_mem32(const struct tag *tag)
514{
515 if (meminfo.nr_banks >= NR_BANKS) {
516 printk(KERN_WARNING
517 "Ignoring memory bank 0x%08x size %dKB\n",
518 tag->u.mem.start, tag->u.mem.size / 1024);
519 return -EINVAL;
520 }
521 meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start;
522 meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size;
523 meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start);
524 meminfo.nr_banks += 1;
525
526 return 0;
527}
528
529__tagtable(ATAG_MEM, parse_tag_mem32);
530
531#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
532struct screen_info screen_info = {
533 .orig_video_lines = 30,
534 .orig_video_cols = 80,
535 .orig_video_mode = 0,
536 .orig_video_ega_bx = 0,
537 .orig_video_isVGA = 1,
538 .orig_video_points = 8
539};
540
541static int __init parse_tag_videotext(const struct tag *tag)
542{
543 screen_info.orig_x = tag->u.videotext.x;
544 screen_info.orig_y = tag->u.videotext.y;
545 screen_info.orig_video_page = tag->u.videotext.video_page;
546 screen_info.orig_video_mode = tag->u.videotext.video_mode;
547 screen_info.orig_video_cols = tag->u.videotext.video_cols;
548 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
549 screen_info.orig_video_lines = tag->u.videotext.video_lines;
550 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
551 screen_info.orig_video_points = tag->u.videotext.video_points;
552 return 0;
553}
554
555__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
556#endif
557
558static int __init parse_tag_ramdisk(const struct tag *tag)
559{
560 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
561 (tag->u.ramdisk.flags & 2) == 0,
562 tag->u.ramdisk.start, tag->u.ramdisk.size);
563 return 0;
564}
565
566__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
567
568static int __init parse_tag_initrd(const struct tag *tag)
569{
570 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
571 "please update your bootloader.\n");
572 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
573 phys_initrd_size = tag->u.initrd.size;
574 return 0;
575}
576
577__tagtable(ATAG_INITRD, parse_tag_initrd);
578
579static int __init parse_tag_initrd2(const struct tag *tag)
580{
581 phys_initrd_start = tag->u.initrd.start;
582 phys_initrd_size = tag->u.initrd.size;
583 return 0;
584}
585
586__tagtable(ATAG_INITRD2, parse_tag_initrd2);
587
588static int __init parse_tag_serialnr(const struct tag *tag)
589{
590 system_serial_low = tag->u.serialnr.low;
591 system_serial_high = tag->u.serialnr.high;
592 return 0;
593}
594
595__tagtable(ATAG_SERIAL, parse_tag_serialnr);
596
597static int __init parse_tag_revision(const struct tag *tag)
598{
599 system_rev = tag->u.revision.rev;
600 return 0;
601}
602
603__tagtable(ATAG_REVISION, parse_tag_revision);
604
605static int __init parse_tag_cmdline(const struct tag *tag)
606{
607 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
608 return 0;
609}
610
611__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
612
613/*
614 * Scan the tag table for this tag, and call its parse function.
615 * The tag table is built by the linker from all the __tagtable
616 * declarations.
617 */
618static int __init parse_tag(const struct tag *tag)
619{
620 extern struct tagtable __tagtable_begin, __tagtable_end;
621 struct tagtable *t;
622
623 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
624 if (tag->hdr.tag == t->tag) {
625 t->parse(tag);
626 break;
627 }
628
629 return t < &__tagtable_end;
630}
631
632/*
633 * Parse all tags in the list, checking both the global and architecture
634 * specific tag tables.
635 */
636static void __init parse_tags(const struct tag *t)
637{
638 for (; t->hdr.size; t = tag_next(t))
639 if (!parse_tag(t))
640 printk(KERN_WARNING
641 "Ignoring unrecognised tag 0x%08x\n",
642 t->hdr.tag);
643}
644
645/*
646 * This holds our defaults.
647 */
648static struct init_tags {
649 struct tag_header hdr1;
650 struct tag_core core;
651 struct tag_header hdr2;
652 struct tag_mem32 mem;
653 struct tag_header hdr3;
654} init_tags __initdata = {
655 { tag_size(tag_core), ATAG_CORE },
656 { 1, PAGE_SIZE, 0xff },
657 { tag_size(tag_mem32), ATAG_MEM },
658 { MEM_SIZE, PHYS_OFFSET },
659 { 0, ATAG_NONE }
660};
661
662static void (*init_machine)(void) __initdata;
663
664static int __init customize_machine(void)
665{
666 /* customizes platform devices, or adds new ones */
667 if (init_machine)
668 init_machine();
669 return 0;
670}
671arch_initcall(customize_machine);
672
673void __init setup_arch(char **cmdline_p)
674{
675 struct tag *tags = (struct tag *)&init_tags;
676 struct machine_desc *mdesc;
677 char *from = default_command_line;
678
679 setup_processor();
680 mdesc = setup_machine(machine_arch_type);
681 machine_name = mdesc->name;
682
683 if (mdesc->soft_reboot)
684 reboot_setup("s");
685
686 if (mdesc->param_offset)
687 tags = phys_to_virt(mdesc->param_offset);
688
689 /*
690 * If we have the old style parameters, convert them to
691 * a tag list.
692 */
693 if (tags->hdr.tag != ATAG_CORE)
694 convert_to_tag_list(tags);
695 if (tags->hdr.tag != ATAG_CORE)
696 tags = (struct tag *)&init_tags;
697
698 if (mdesc->fixup)
699 mdesc->fixup(mdesc, tags, &from, &meminfo);
700
701 if (tags->hdr.tag == ATAG_CORE) {
702 if (meminfo.nr_banks != 0)
703 squash_mem_tags(tags);
704 parse_tags(tags);
705 }
706
707 init_mm.start_code = (unsigned long) &_text;
708 init_mm.end_code = (unsigned long) &_etext;
709 init_mm.end_data = (unsigned long) &_edata;
710 init_mm.brk = (unsigned long) &_end;
711
712 memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
713 saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
714 parse_cmdline(cmdline_p, from);
715 paging_init(&meminfo, mdesc);
716 request_standard_resources(&meminfo, mdesc);
717
718 /*
719 * Set up various architecture-specific pointers
720 */
721 init_arch_irq = mdesc->init_irq;
722 system_timer = mdesc->timer;
723 init_machine = mdesc->init_machine;
724
725#ifdef CONFIG_VT
726#if defined(CONFIG_VGA_CONSOLE)
727 conswitchp = &vga_con;
728#elif defined(CONFIG_DUMMY_CONSOLE)
729 conswitchp = &dummy_con;
730#endif
731#endif
732}
733
734
735static int __init topology_init(void)
736{
737 int cpu;
738
739 for_each_cpu(cpu)
740 register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu, NULL);
741
742 return 0;
743}
744
745subsys_initcall(topology_init);
746
747static const char *hwcap_str[] = {
748 "swp",
749 "half",
750 "thumb",
751 "26bit",
752 "fastmult",
753 "fpa",
754 "vfp",
755 "edsp",
756 "java",
757 NULL
758};
759
760static void
761c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
762{
763 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
764
765 seq_printf(m, "%s size\t\t: %d\n"
766 "%s assoc\t\t: %d\n"
767 "%s line length\t: %d\n"
768 "%s sets\t\t: %d\n",
769 type, mult << (8 + CACHE_SIZE(cache)),
770 type, (mult << CACHE_ASSOC(cache)) >> 1,
771 type, 8 << CACHE_LINE(cache),
772 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
773 CACHE_LINE(cache)));
774}
775
776static int c_show(struct seq_file *m, void *v)
777{
778 int i;
779
780 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
781 cpu_name, (int)processor_id & 15, elf_platform);
782
783#if defined(CONFIG_SMP)
784 for_each_online_cpu(i) {
785 seq_printf(m, "Processor\t: %d\n", i);
786 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
787 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
788 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
789 }
790#else /* CONFIG_SMP */
791 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
792 loops_per_jiffy / (500000/HZ),
793 (loops_per_jiffy / (5000/HZ)) % 100);
794#endif
795
796 /* dump out the processor features */
797 seq_puts(m, "Features\t: ");
798
799 for (i = 0; hwcap_str[i]; i++)
800 if (elf_hwcap & (1 << i))
801 seq_printf(m, "%s ", hwcap_str[i]);
802
803 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
804 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
805
806 if ((processor_id & 0x0000f000) == 0x00000000) {
807 /* pre-ARM7 */
808 seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
809 } else {
810 if ((processor_id & 0x0000f000) == 0x00007000) {
811 /* ARM7 */
812 seq_printf(m, "CPU variant\t: 0x%02x\n",
813 (processor_id >> 16) & 127);
814 } else {
815 /* post-ARM7 */
816 seq_printf(m, "CPU variant\t: 0x%x\n",
817 (processor_id >> 20) & 15);
818 }
819 seq_printf(m, "CPU part\t: 0x%03x\n",
820 (processor_id >> 4) & 0xfff);
821 }
822 seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
823
824 {
825 unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
826 if (cache_info != processor_id) {
827 seq_printf(m, "Cache type\t: %s\n"
828 "Cache clean\t: %s\n"
829 "Cache lockdown\t: %s\n"
830 "Cache format\t: %s\n",
831 cache_types[CACHE_TYPE(cache_info)],
832 cache_clean[CACHE_TYPE(cache_info)],
833 cache_lockdown[CACHE_TYPE(cache_info)],
834 CACHE_S(cache_info) ? "Harvard" : "Unified");
835
836 if (CACHE_S(cache_info)) {
837 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
838 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
839 } else {
840 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
841 }
842 }
843 }
844
845 seq_puts(m, "\n");
846
847 seq_printf(m, "Hardware\t: %s\n", machine_name);
848 seq_printf(m, "Revision\t: %04x\n", system_rev);
849 seq_printf(m, "Serial\t\t: %08x%08x\n",
850 system_serial_high, system_serial_low);
851
852 return 0;
853}
854
855static void *c_start(struct seq_file *m, loff_t *pos)
856{
857 return *pos < 1 ? (void *)1 : NULL;
858}
859
860static void *c_next(struct seq_file *m, void *v, loff_t *pos)
861{
862 ++*pos;
863 return NULL;
864}
865
866static void c_stop(struct seq_file *m, void *v)
867{
868}
869
870struct seq_operations cpuinfo_op = {
871 .start = c_start,
872 .next = c_next,
873 .stop = c_stop,
874 .show = c_show
875};