linux/arch/xtensa/kernel/setup.c
<<
>>
Prefs
   1/*
   2 * arch/xtensa/kernel/setup.c
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * Copyright (C) 1995  Linus Torvalds
   9 * Copyright (C) 2001 - 2005  Tensilica Inc.
  10 *
  11 * Chris Zankel <chris@zankel.net>
  12 * Joe Taylor   <joe@tensilica.com, joetylr@yahoo.com>
  13 * Kevin Chea
  14 * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
  15 */
  16
  17#include <linux/errno.h>
  18#include <linux/init.h>
  19#include <linux/mm.h>
  20#include <linux/proc_fs.h>
  21#include <linux/screen_info.h>
  22#include <linux/bootmem.h>
  23#include <linux/kernel.h>
  24#include <linux/percpu.h>
  25#include <linux/clk-provider.h>
  26#include <linux/cpu.h>
  27#include <linux/of_fdt.h>
  28#include <linux/of_platform.h>
  29
  30#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
  31# include <linux/console.h>
  32#endif
  33
  34#ifdef CONFIG_RTC
  35# include <linux/timex.h>
  36#endif
  37
  38#ifdef CONFIG_PROC_FS
  39# include <linux/seq_file.h>
  40#endif
  41
  42#include <asm/bootparam.h>
  43#include <asm/mmu_context.h>
  44#include <asm/pgtable.h>
  45#include <asm/processor.h>
  46#include <asm/timex.h>
  47#include <asm/platform.h>
  48#include <asm/page.h>
  49#include <asm/setup.h>
  50#include <asm/param.h>
  51#include <asm/traps.h>
  52#include <asm/smp.h>
  53
  54#include <platform/hardware.h>
  55
  56#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
  57struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
  58#endif
  59
  60#ifdef CONFIG_BLK_DEV_FD
  61extern struct fd_ops no_fd_ops;
  62struct fd_ops *fd_ops;
  63#endif
  64
  65extern struct rtc_ops no_rtc_ops;
  66struct rtc_ops *rtc_ops;
  67
  68#ifdef CONFIG_BLK_DEV_INITRD
  69extern unsigned long initrd_start;
  70extern unsigned long initrd_end;
  71int initrd_is_mapped = 0;
  72extern int initrd_below_start_ok;
  73#endif
  74
  75#ifdef CONFIG_OF
  76extern u32 __dtb_start[];
  77void *dtb_start = __dtb_start;
  78#endif
  79
  80unsigned char aux_device_present;
  81extern unsigned long loops_per_jiffy;
  82
  83/* Command line specified as configuration option. */
  84
  85static char __initdata command_line[COMMAND_LINE_SIZE];
  86
  87#ifdef CONFIG_CMDLINE_BOOL
  88static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
  89#endif
  90
  91sysmem_info_t __initdata sysmem;
  92
  93extern int mem_reserve(unsigned long, unsigned long, int);
  94extern void bootmem_init(void);
  95extern void zones_init(void);
  96
  97/*
  98 * Boot parameter parsing.
  99 *
 100 * The Xtensa port uses a list of variable-sized tags to pass data to
 101 * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
 102 * to be recognised. The list is terminated with a zero-sized
 103 * BP_TAG_LAST tag.
 104 */
 105
 106typedef struct tagtable {
 107        u32 tag;
 108        int (*parse)(const bp_tag_t*);
 109} tagtable_t;
 110
 111#define __tagtable(tag, fn) static tagtable_t __tagtable_##fn           \
 112        __attribute__((used, section(".taglist"))) = { tag, fn }
 113
 114/* parse current tag */
 115
 116static int __init add_sysmem_bank(unsigned long type, unsigned long start,
 117                unsigned long end)
 118{
 119        if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
 120                printk(KERN_WARNING
 121                                "Ignoring memory bank 0x%08lx size %ldKB\n",
 122                                start, end - start);
 123                return -EINVAL;
 124        }
 125        sysmem.bank[sysmem.nr_banks].type  = type;
 126        sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
 127        sysmem.bank[sysmem.nr_banks].end   = end & PAGE_MASK;
 128        sysmem.nr_banks++;
 129
 130        return 0;
 131}
 132
 133static int __init parse_tag_mem(const bp_tag_t *tag)
 134{
 135        meminfo_t *mi = (meminfo_t *)(tag->data);
 136
 137        if (mi->type != MEMORY_TYPE_CONVENTIONAL)
 138                return -1;
 139
 140        return add_sysmem_bank(mi->type, mi->start, mi->end);
 141}
 142
 143__tagtable(BP_TAG_MEMORY, parse_tag_mem);
 144
 145#ifdef CONFIG_BLK_DEV_INITRD
 146
 147static int __init parse_tag_initrd(const bp_tag_t* tag)
 148{
 149        meminfo_t* mi;
 150        mi = (meminfo_t*)(tag->data);
 151        initrd_start = (unsigned long)__va(mi->start);
 152        initrd_end = (unsigned long)__va(mi->end);
 153
 154        return 0;
 155}
 156
 157__tagtable(BP_TAG_INITRD, parse_tag_initrd);
 158
 159#ifdef CONFIG_OF
 160
 161static int __init parse_tag_fdt(const bp_tag_t *tag)
 162{
 163        dtb_start = __va(tag->data[0]);
 164        return 0;
 165}
 166
 167__tagtable(BP_TAG_FDT, parse_tag_fdt);
 168
 169#endif /* CONFIG_OF */
 170
 171#endif /* CONFIG_BLK_DEV_INITRD */
 172
 173static int __init parse_tag_cmdline(const bp_tag_t* tag)
 174{
 175        strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
 176        return 0;
 177}
 178
 179__tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
 180
 181static int __init parse_bootparam(const bp_tag_t* tag)
 182{
 183        extern tagtable_t __tagtable_begin, __tagtable_end;
 184        tagtable_t *t;
 185
 186        /* Boot parameters must start with a BP_TAG_FIRST tag. */
 187
 188        if (tag->id != BP_TAG_FIRST) {
 189                printk(KERN_WARNING "Invalid boot parameters!\n");
 190                return 0;
 191        }
 192
 193        tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
 194
 195        /* Parse all tags. */
 196
 197        while (tag != NULL && tag->id != BP_TAG_LAST) {
 198                for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
 199                        if (tag->id == t->tag) {
 200                                t->parse(tag);
 201                                break;
 202                        }
 203                }
 204                if (t == &__tagtable_end)
 205                        printk(KERN_WARNING "Ignoring tag "
 206                               "0x%08x\n", tag->id);
 207                tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
 208        }
 209
 210        return 0;
 211}
 212
 213#ifdef CONFIG_OF
 214bool __initdata dt_memory_scan = false;
 215
 216#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
 217unsigned long xtensa_kio_paddr = XCHAL_KIO_DEFAULT_PADDR;
 218EXPORT_SYMBOL(xtensa_kio_paddr);
 219
 220static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
 221                int depth, void *data)
 222{
 223        const __be32 *ranges;
 224        unsigned long len;
 225
 226        if (depth > 1)
 227                return 0;
 228
 229        if (!of_flat_dt_is_compatible(node, "simple-bus"))
 230                return 0;
 231
 232        ranges = of_get_flat_dt_prop(node, "ranges", &len);
 233        if (!ranges)
 234                return 1;
 235        if (len == 0)
 236                return 1;
 237
 238        xtensa_kio_paddr = of_read_ulong(ranges+1, 1);
 239        /* round down to nearest 256MB boundary */
 240        xtensa_kio_paddr &= 0xf0000000;
 241
 242        return 1;
 243}
 244#else
 245static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
 246                int depth, void *data)
 247{
 248        return 1;
 249}
 250#endif
 251
 252void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 253{
 254        if (!dt_memory_scan)
 255                return;
 256
 257        size &= PAGE_MASK;
 258        add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
 259}
 260
 261void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 262{
 263        return __alloc_bootmem(size, align, 0);
 264}
 265
 266void __init early_init_devtree(void *params)
 267{
 268        if (sysmem.nr_banks == 0)
 269                dt_memory_scan = true;
 270
 271        early_init_dt_scan(params);
 272        of_scan_flat_dt(xtensa_dt_io_area, NULL);
 273
 274        if (!command_line[0])
 275                strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
 276}
 277
 278static int __init xtensa_device_probe(void)
 279{
 280        of_clk_init(NULL);
 281        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 282        return 0;
 283}
 284
 285device_initcall(xtensa_device_probe);
 286
 287#endif /* CONFIG_OF */
 288
 289/*
 290 * Initialize architecture. (Early stage)
 291 */
 292
 293void __init init_arch(bp_tag_t *bp_start)
 294{
 295        sysmem.nr_banks = 0;
 296
 297        /* Parse boot parameters */
 298
 299        if (bp_start)
 300                parse_bootparam(bp_start);
 301
 302#ifdef CONFIG_OF
 303        early_init_devtree(dtb_start);
 304#endif
 305
 306        if (sysmem.nr_banks == 0) {
 307                sysmem.nr_banks = 1;
 308                sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
 309                sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
 310                                     + PLATFORM_DEFAULT_MEM_SIZE;
 311        }
 312
 313#ifdef CONFIG_CMDLINE_BOOL
 314        if (!command_line[0])
 315                strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
 316#endif
 317
 318        /* Early hook for platforms */
 319
 320        platform_init(bp_start);
 321
 322        /* Initialize MMU. */
 323
 324        init_mmu();
 325}
 326
 327/*
 328 * Initialize system. Setup memory and reserve regions.
 329 */
 330
 331extern char _end;
 332extern char _stext;
 333extern char _WindowVectors_text_start;
 334extern char _WindowVectors_text_end;
 335extern char _DebugInterruptVector_literal_start;
 336extern char _DebugInterruptVector_text_end;
 337extern char _KernelExceptionVector_literal_start;
 338extern char _KernelExceptionVector_text_end;
 339extern char _UserExceptionVector_literal_start;
 340extern char _UserExceptionVector_text_end;
 341extern char _DoubleExceptionVector_literal_start;
 342extern char _DoubleExceptionVector_text_end;
 343#if XCHAL_EXCM_LEVEL >= 2
 344extern char _Level2InterruptVector_text_start;
 345extern char _Level2InterruptVector_text_end;
 346#endif
 347#if XCHAL_EXCM_LEVEL >= 3
 348extern char _Level3InterruptVector_text_start;
 349extern char _Level3InterruptVector_text_end;
 350#endif
 351#if XCHAL_EXCM_LEVEL >= 4
 352extern char _Level4InterruptVector_text_start;
 353extern char _Level4InterruptVector_text_end;
 354#endif
 355#if XCHAL_EXCM_LEVEL >= 5
 356extern char _Level5InterruptVector_text_start;
 357extern char _Level5InterruptVector_text_end;
 358#endif
 359#if XCHAL_EXCM_LEVEL >= 6
 360extern char _Level6InterruptVector_text_start;
 361extern char _Level6InterruptVector_text_end;
 362#endif
 363
 364
 365
 366#ifdef CONFIG_S32C1I_SELFTEST
 367#if XCHAL_HAVE_S32C1I
 368
 369static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
 370
 371/*
 372 * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
 373 *
 374 * If *v == cmp, set *v = set.  Return previous *v.
 375 */
 376static inline int probed_compare_swap(int *v, int cmp, int set)
 377{
 378        int tmp;
 379
 380        __asm__ __volatile__(
 381                        "       movi    %1, 1f\n"
 382                        "       s32i    %1, %4, 0\n"
 383                        "       wsr     %2, scompare1\n"
 384                        "1:     s32c1i  %0, %3, 0\n"
 385                        : "=a" (set), "=&a" (tmp)
 386                        : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
 387                        : "memory"
 388                        );
 389        return set;
 390}
 391
 392/* Handle probed exception */
 393
 394static void __init do_probed_exception(struct pt_regs *regs,
 395                unsigned long exccause)
 396{
 397        if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
 398                regs->pc += 3;          /* skip the s32c1i instruction */
 399                rcw_exc = exccause;
 400        } else {
 401                do_unhandled(regs, exccause);
 402        }
 403}
 404
 405/* Simple test of S32C1I (soc bringup assist) */
 406
 407static int __init check_s32c1i(void)
 408{
 409        int n, cause1, cause2;
 410        void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
 411
 412        rcw_probe_pc = 0;
 413        handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
 414                        do_probed_exception);
 415        handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
 416                        do_probed_exception);
 417        handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
 418                        do_probed_exception);
 419
 420        /* First try an S32C1I that does not store: */
 421        rcw_exc = 0;
 422        rcw_word = 1;
 423        n = probed_compare_swap(&rcw_word, 0, 2);
 424        cause1 = rcw_exc;
 425
 426        /* took exception? */
 427        if (cause1 != 0) {
 428                /* unclean exception? */
 429                if (n != 2 || rcw_word != 1)
 430                        panic("S32C1I exception error");
 431        } else if (rcw_word != 1 || n != 1) {
 432                panic("S32C1I compare error");
 433        }
 434
 435        /* Then an S32C1I that stores: */
 436        rcw_exc = 0;
 437        rcw_word = 0x1234567;
 438        n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
 439        cause2 = rcw_exc;
 440
 441        if (cause2 != 0) {
 442                /* unclean exception? */
 443                if (n != 0xabcde || rcw_word != 0x1234567)
 444                        panic("S32C1I exception error (b)");
 445        } else if (rcw_word != 0xabcde || n != 0x1234567) {
 446                panic("S32C1I store error");
 447        }
 448
 449        /* Verify consistency of exceptions: */
 450        if (cause1 || cause2) {
 451                pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
 452                /* If emulation of S32C1I upon bus error gets implemented,
 453                   we can get rid of this panic for single core (not SMP) */
 454                panic("S32C1I exceptions not currently supported");
 455        }
 456        if (cause1 != cause2)
 457                panic("inconsistent S32C1I exceptions");
 458
 459        trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
 460        trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
 461        trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
 462        return 0;
 463}
 464
 465#else /* XCHAL_HAVE_S32C1I */
 466
 467/* This condition should not occur with a commercially deployed processor.
 468   Display reminder for early engr test or demo chips / FPGA bitstreams */
 469static int __init check_s32c1i(void)
 470{
 471        pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
 472        return 0;
 473}
 474
 475#endif /* XCHAL_HAVE_S32C1I */
 476early_initcall(check_s32c1i);
 477#endif /* CONFIG_S32C1I_SELFTEST */
 478
 479
 480void __init setup_arch(char **cmdline_p)
 481{
 482        strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
 483        *cmdline_p = command_line;
 484
 485        /* Reserve some memory regions */
 486
 487#ifdef CONFIG_BLK_DEV_INITRD
 488        if (initrd_start < initrd_end) {
 489                initrd_is_mapped = mem_reserve(__pa(initrd_start),
 490                                               __pa(initrd_end), 0);
 491                initrd_below_start_ok = 1;
 492        } else {
 493                initrd_start = 0;
 494        }
 495#endif
 496
 497        mem_reserve(__pa(&_stext),__pa(&_end), 1);
 498
 499        mem_reserve(__pa(&_WindowVectors_text_start),
 500                    __pa(&_WindowVectors_text_end), 0);
 501
 502        mem_reserve(__pa(&_DebugInterruptVector_literal_start),
 503                    __pa(&_DebugInterruptVector_text_end), 0);
 504
 505        mem_reserve(__pa(&_KernelExceptionVector_literal_start),
 506                    __pa(&_KernelExceptionVector_text_end), 0);
 507
 508        mem_reserve(__pa(&_UserExceptionVector_literal_start),
 509                    __pa(&_UserExceptionVector_text_end), 0);
 510
 511        mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
 512                    __pa(&_DoubleExceptionVector_text_end), 0);
 513
 514#if XCHAL_EXCM_LEVEL >= 2
 515        mem_reserve(__pa(&_Level2InterruptVector_text_start),
 516                    __pa(&_Level2InterruptVector_text_end), 0);
 517#endif
 518#if XCHAL_EXCM_LEVEL >= 3
 519        mem_reserve(__pa(&_Level3InterruptVector_text_start),
 520                    __pa(&_Level3InterruptVector_text_end), 0);
 521#endif
 522#if XCHAL_EXCM_LEVEL >= 4
 523        mem_reserve(__pa(&_Level4InterruptVector_text_start),
 524                    __pa(&_Level4InterruptVector_text_end), 0);
 525#endif
 526#if XCHAL_EXCM_LEVEL >= 5
 527        mem_reserve(__pa(&_Level5InterruptVector_text_start),
 528                    __pa(&_Level5InterruptVector_text_end), 0);
 529#endif
 530#if XCHAL_EXCM_LEVEL >= 6
 531        mem_reserve(__pa(&_Level6InterruptVector_text_start),
 532                    __pa(&_Level6InterruptVector_text_end), 0);
 533#endif
 534
 535        bootmem_init();
 536
 537        unflatten_and_copy_device_tree();
 538
 539        platform_setup(cmdline_p);
 540
 541#ifdef CONFIG_SMP
 542        smp_init_cpus();
 543#endif
 544
 545        paging_init();
 546        zones_init();
 547
 548#ifdef CONFIG_VT
 549# if defined(CONFIG_VGA_CONSOLE)
 550        conswitchp = &vga_con;
 551# elif defined(CONFIG_DUMMY_CONSOLE)
 552        conswitchp = &dummy_con;
 553# endif
 554#endif
 555
 556#ifdef CONFIG_PCI
 557        platform_pcibios_init();
 558#endif
 559}
 560
 561static DEFINE_PER_CPU(struct cpu, cpu_data);
 562
 563static int __init topology_init(void)
 564{
 565        int i;
 566
 567        for_each_possible_cpu(i) {
 568                struct cpu *cpu = &per_cpu(cpu_data, i);
 569                cpu->hotpluggable = !!i;
 570                register_cpu(cpu, i);
 571        }
 572
 573        return 0;
 574}
 575subsys_initcall(topology_init);
 576
 577void machine_restart(char * cmd)
 578{
 579        platform_restart();
 580}
 581
 582void machine_halt(void)
 583{
 584        platform_halt();
 585        while (1);
 586}
 587
 588void machine_power_off(void)
 589{
 590        platform_power_off();
 591        while (1);
 592}
 593#ifdef CONFIG_PROC_FS
 594
 595/*
 596 * Display some core information through /proc/cpuinfo.
 597 */
 598
 599static int
 600c_show(struct seq_file *f, void *slot)
 601{
 602        char buf[NR_CPUS * 5];
 603
 604        cpulist_scnprintf(buf, sizeof(buf), cpu_online_mask);
 605        /* high-level stuff */
 606        seq_printf(f, "CPU count\t: %u\n"
 607                      "CPU list\t: %s\n"
 608                      "vendor_id\t: Tensilica\n"
 609                      "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
 610                      "core ID\t\t: " XCHAL_CORE_ID "\n"
 611                      "build ID\t: 0x%x\n"
 612                      "byte order\t: %s\n"
 613                      "cpu MHz\t\t: %lu.%02lu\n"
 614                      "bogomips\t: %lu.%02lu\n",
 615                      num_online_cpus(),
 616                      buf,
 617                      XCHAL_BUILD_UNIQUE_ID,
 618                      XCHAL_HAVE_BE ?  "big" : "little",
 619                      ccount_freq/1000000,
 620                      (ccount_freq/10000) % 100,
 621                      loops_per_jiffy/(500000/HZ),
 622                      (loops_per_jiffy/(5000/HZ)) % 100);
 623
 624        seq_printf(f,"flags\t\t: "
 625#if XCHAL_HAVE_NMI
 626                     "nmi "
 627#endif
 628#if XCHAL_HAVE_DEBUG
 629                     "debug "
 630# if XCHAL_HAVE_OCD
 631                     "ocd "
 632# endif
 633#endif
 634#if XCHAL_HAVE_DENSITY
 635                     "density "
 636#endif
 637#if XCHAL_HAVE_BOOLEANS
 638                     "boolean "
 639#endif
 640#if XCHAL_HAVE_LOOPS
 641                     "loop "
 642#endif
 643#if XCHAL_HAVE_NSA
 644                     "nsa "
 645#endif
 646#if XCHAL_HAVE_MINMAX
 647                     "minmax "
 648#endif
 649#if XCHAL_HAVE_SEXT
 650                     "sext "
 651#endif
 652#if XCHAL_HAVE_CLAMPS
 653                     "clamps "
 654#endif
 655#if XCHAL_HAVE_MAC16
 656                     "mac16 "
 657#endif
 658#if XCHAL_HAVE_MUL16
 659                     "mul16 "
 660#endif
 661#if XCHAL_HAVE_MUL32
 662                     "mul32 "
 663#endif
 664#if XCHAL_HAVE_MUL32_HIGH
 665                     "mul32h "
 666#endif
 667#if XCHAL_HAVE_FP
 668                     "fpu "
 669#endif
 670#if XCHAL_HAVE_S32C1I
 671                     "s32c1i "
 672#endif
 673                     "\n");
 674
 675        /* Registers. */
 676        seq_printf(f,"physical aregs\t: %d\n"
 677                     "misc regs\t: %d\n"
 678                     "ibreak\t\t: %d\n"
 679                     "dbreak\t\t: %d\n",
 680                     XCHAL_NUM_AREGS,
 681                     XCHAL_NUM_MISC_REGS,
 682                     XCHAL_NUM_IBREAK,
 683                     XCHAL_NUM_DBREAK);
 684
 685
 686        /* Interrupt. */
 687        seq_printf(f,"num ints\t: %d\n"
 688                     "ext ints\t: %d\n"
 689                     "int levels\t: %d\n"
 690                     "timers\t\t: %d\n"
 691                     "debug level\t: %d\n",
 692                     XCHAL_NUM_INTERRUPTS,
 693                     XCHAL_NUM_EXTINTERRUPTS,
 694                     XCHAL_NUM_INTLEVELS,
 695                     XCHAL_NUM_TIMERS,
 696                     XCHAL_DEBUGLEVEL);
 697
 698        /* Cache */
 699        seq_printf(f,"icache line size: %d\n"
 700                     "icache ways\t: %d\n"
 701                     "icache size\t: %d\n"
 702                     "icache flags\t: "
 703#if XCHAL_ICACHE_LINE_LOCKABLE
 704                     "lock "
 705#endif
 706                     "\n"
 707                     "dcache line size: %d\n"
 708                     "dcache ways\t: %d\n"
 709                     "dcache size\t: %d\n"
 710                     "dcache flags\t: "
 711#if XCHAL_DCACHE_IS_WRITEBACK
 712                     "writeback "
 713#endif
 714#if XCHAL_DCACHE_LINE_LOCKABLE
 715                     "lock "
 716#endif
 717                     "\n",
 718                     XCHAL_ICACHE_LINESIZE,
 719                     XCHAL_ICACHE_WAYS,
 720                     XCHAL_ICACHE_SIZE,
 721                     XCHAL_DCACHE_LINESIZE,
 722                     XCHAL_DCACHE_WAYS,
 723                     XCHAL_DCACHE_SIZE);
 724
 725        return 0;
 726}
 727
 728/*
 729 * We show only CPU #0 info.
 730 */
 731static void *
 732c_start(struct seq_file *f, loff_t *pos)
 733{
 734        return (*pos == 0) ? (void *)1 : NULL;
 735}
 736
 737static void *
 738c_next(struct seq_file *f, void *v, loff_t *pos)
 739{
 740        return NULL;
 741}
 742
 743static void
 744c_stop(struct seq_file *f, void *v)
 745{
 746}
 747
 748const struct seq_operations cpuinfo_op =
 749{
 750        .start  = c_start,
 751        .next   = c_next,
 752        .stop   = c_stop,
 753        .show   = c_show,
 754};
 755
 756#endif /* CONFIG_PROC_FS */
 757