1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/alpha/kernel/setup.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1995 Linus Torvalds
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds /* 2.3.x bootmem, 1999 Andrea Arcangeli <andrea@suse.de> */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds /*
111da177e4SLinus Torvalds * Bootup setup stuff.
121da177e4SLinus Torvalds */
131da177e4SLinus Torvalds
141da177e4SLinus Torvalds #include <linux/sched.h>
151da177e4SLinus Torvalds #include <linux/kernel.h>
161da177e4SLinus Torvalds #include <linux/mm.h>
171da177e4SLinus Torvalds #include <linux/stddef.h>
181da177e4SLinus Torvalds #include <linux/unistd.h>
191da177e4SLinus Torvalds #include <linux/ptrace.h>
201da177e4SLinus Torvalds #include <linux/slab.h>
211da177e4SLinus Torvalds #include <linux/user.h>
22894673eeSJon Smirl #include <linux/screen_info.h>
231da177e4SLinus Torvalds #include <linux/delay.h>
241da177e4SLinus Torvalds #include <linux/mc146818rtc.h>
251da177e4SLinus Torvalds #include <linux/console.h>
26917b1f78SBrian Uhrain says #include <linux/cpu.h>
271da177e4SLinus Torvalds #include <linux/errno.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/string.h>
301da177e4SLinus Torvalds #include <linux/ioport.h>
31f39650deSAndy Shevchenko #include <linux/panic_notifier.h>
32e5c6c8e4SMichael Neuling #include <linux/platform_device.h>
336471f52aSMike Rapoport #include <linux/memblock.h>
341da177e4SLinus Torvalds #include <linux/pci.h>
351da177e4SLinus Torvalds #include <linux/seq_file.h>
361da177e4SLinus Torvalds #include <linux/root_dev.h>
371da177e4SLinus Torvalds #include <linux/initrd.h>
381da177e4SLinus Torvalds #include <linux/eisa.h>
3922a9835cSDave Hansen #include <linux/pfn.h>
401da177e4SLinus Torvalds #ifdef CONFIG_MAGIC_SYSRQ
411da177e4SLinus Torvalds #include <linux/sysrq.h>
421da177e4SLinus Torvalds #include <linux/reboot.h>
431da177e4SLinus Torvalds #endif
441da177e4SLinus Torvalds #include <linux/notifier.h>
451da177e4SLinus Torvalds #include <asm/setup.h>
461da177e4SLinus Torvalds #include <asm/io.h>
4774fd1b68SRichard Henderson #include <linux/log2.h>
4800cd1176SPaul Gortmaker #include <linux/export.h>
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds static int alpha_panic_event(struct notifier_block *, unsigned long, void *);
511da177e4SLinus Torvalds static struct notifier_block alpha_panic_block = {
521da177e4SLinus Torvalds alpha_panic_event,
531da177e4SLinus Torvalds NULL,
541da177e4SLinus Torvalds INT_MAX /* try to do it first */
551da177e4SLinus Torvalds };
561da177e4SLinus Torvalds
577c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
581da177e4SLinus Torvalds #include <asm/hwrpb.h>
591da177e4SLinus Torvalds #include <asm/dma.h>
601da177e4SLinus Torvalds #include <asm/mmu_context.h>
611da177e4SLinus Torvalds #include <asm/console.h>
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds #include "proto.h"
641da177e4SLinus Torvalds #include "pci_impl.h"
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds struct hwrpb_struct *hwrpb;
68cff52dafSAl Viro EXPORT_SYMBOL(hwrpb);
691da177e4SLinus Torvalds unsigned long srm_hae;
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds int alpha_l1i_cacheshape;
721da177e4SLinus Torvalds int alpha_l1d_cacheshape;
731da177e4SLinus Torvalds int alpha_l2_cacheshape;
741da177e4SLinus Torvalds int alpha_l3_cacheshape;
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
771da177e4SLinus Torvalds /* 0=minimum, 1=verbose, 2=all */
781da177e4SLinus Torvalds /* These can be overridden via the command line, ie "verbose_mcheck=2") */
791da177e4SLinus Torvalds unsigned long alpha_verbose_mcheck = CONFIG_VERBOSE_MCHECK_ON;
801da177e4SLinus Torvalds #endif
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds /* Which processor we booted from. */
831da177e4SLinus Torvalds int boot_cpuid;
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds /*
861da177e4SLinus Torvalds * Using SRM callbacks for initial console output. This works from
871da177e4SLinus Torvalds * setup_arch() time through the end of time_init(), as those places
881da177e4SLinus Torvalds * are under our (Alpha) control.
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds * "srmcons" specified in the boot command arguments allows us to
911da177e4SLinus Torvalds * see kernel messages during the period of time before the true
921da177e4SLinus Torvalds * console device is "registered" during console_init().
931da177e4SLinus Torvalds * As of this version (2.5.59), console_init() will call
941da177e4SLinus Torvalds * disable_early_printk() as the last action before initializing
951da177e4SLinus Torvalds * the console drivers. That's the last possible time srmcons can be
961da177e4SLinus Torvalds * unregistered without interfering with console behavior.
971da177e4SLinus Torvalds *
981da177e4SLinus Torvalds * By default, OFF; set it with a bootcommand arg of "srmcons" or
991da177e4SLinus Torvalds * "console=srm". The meaning of these two args is:
1001da177e4SLinus Torvalds * "srmcons" - early callback prints
1011da177e4SLinus Torvalds * "console=srm" - full callback based console, including early prints
1021da177e4SLinus Torvalds */
1031da177e4SLinus Torvalds int srmcons_output = 0;
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds /* Enforce a memory size limit; useful for testing. By default, none. */
1061da177e4SLinus Torvalds unsigned long mem_size_limit = 0;
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds /* Set AGP GART window size (0 means disabled). */
1091da177e4SLinus Torvalds unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE;
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds #ifdef CONFIG_ALPHA_GENERIC
1121da177e4SLinus Torvalds struct alpha_machine_vector alpha_mv;
11300fc0e0dSAl Viro EXPORT_SYMBOL(alpha_mv);
114994dcf70SRichard Henderson #endif
115994dcf70SRichard Henderson
116994dcf70SRichard Henderson #ifndef alpha_using_srm
1171da177e4SLinus Torvalds int alpha_using_srm;
118cff52dafSAl Viro EXPORT_SYMBOL(alpha_using_srm);
1191da177e4SLinus Torvalds #endif
1201da177e4SLinus Torvalds
121994dcf70SRichard Henderson #ifndef alpha_using_qemu
122994dcf70SRichard Henderson int alpha_using_qemu;
123994dcf70SRichard Henderson #endif
124994dcf70SRichard Henderson
1251da177e4SLinus Torvalds static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long,
1261da177e4SLinus Torvalds unsigned long);
1271da177e4SLinus Torvalds static struct alpha_machine_vector *get_sysvec_byname(const char *);
1281da177e4SLinus Torvalds static void get_sysnames(unsigned long, unsigned long, unsigned long,
1291da177e4SLinus Torvalds char **, char **);
1301da177e4SLinus Torvalds static void determine_cpu_caches (unsigned int);
1311da177e4SLinus Torvalds
1323c253ca0SAlon Bar-Lev static char __initdata command_line[COMMAND_LINE_SIZE];
1331da177e4SLinus Torvalds
134*d9a5d5c4SArnd Bergmann #ifdef CONFIG_VGA_CONSOLE
1351da177e4SLinus Torvalds /*
1361da177e4SLinus Torvalds * The format of "screen_info" is strange, and due to early
1371da177e4SLinus Torvalds * i386-setup code. This is just enough to make the console
1381da177e4SLinus Torvalds * code think we're on a VGA color display.
1391da177e4SLinus Torvalds */
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds struct screen_info screen_info = {
1421da177e4SLinus Torvalds .orig_x = 0,
1431da177e4SLinus Torvalds .orig_y = 25,
1441da177e4SLinus Torvalds .orig_video_cols = 80,
1451da177e4SLinus Torvalds .orig_video_lines = 25,
1461da177e4SLinus Torvalds .orig_video_isVGA = 1,
1471da177e4SLinus Torvalds .orig_video_points = 16
1481da177e4SLinus Torvalds };
1491da177e4SLinus Torvalds
150cff52dafSAl Viro EXPORT_SYMBOL(screen_info);
151*d9a5d5c4SArnd Bergmann #endif
152cff52dafSAl Viro
1531da177e4SLinus Torvalds /*
1541da177e4SLinus Torvalds * The direct map I/O window, if any. This should be the same
1551da177e4SLinus Torvalds * for all busses, since it's used by virt_to_bus.
1561da177e4SLinus Torvalds */
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds unsigned long __direct_map_base;
1591da177e4SLinus Torvalds unsigned long __direct_map_size;
160cff52dafSAl Viro EXPORT_SYMBOL(__direct_map_base);
161cff52dafSAl Viro EXPORT_SYMBOL(__direct_map_size);
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds /*
1641da177e4SLinus Torvalds * Declare all of the machine vectors.
1651da177e4SLinus Torvalds */
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds /* GCC 2.7.2 (on alpha at least) is lame. It does not support either
1681da177e4SLinus Torvalds __attribute__((weak)) or #pragma weak. Bypass it and talk directly
1691da177e4SLinus Torvalds to the assembler. */
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds #define WEAK(X) \
1721da177e4SLinus Torvalds extern struct alpha_machine_vector X; \
1731da177e4SLinus Torvalds asm(".weak "#X)
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds WEAK(alcor_mv);
1761da177e4SLinus Torvalds WEAK(alphabook1_mv);
1771da177e4SLinus Torvalds WEAK(avanti_mv);
1781da177e4SLinus Torvalds WEAK(cabriolet_mv);
1791da177e4SLinus Torvalds WEAK(clipper_mv);
1801da177e4SLinus Torvalds WEAK(dp264_mv);
1811da177e4SLinus Torvalds WEAK(eb164_mv);
1821da177e4SLinus Torvalds WEAK(eb64p_mv);
1831da177e4SLinus Torvalds WEAK(eb66_mv);
1841da177e4SLinus Torvalds WEAK(eb66p_mv);
1851da177e4SLinus Torvalds WEAK(eiger_mv);
1861da177e4SLinus Torvalds WEAK(jensen_mv);
1871da177e4SLinus Torvalds WEAK(lx164_mv);
1881da177e4SLinus Torvalds WEAK(lynx_mv);
1891da177e4SLinus Torvalds WEAK(marvel_ev7_mv);
1901da177e4SLinus Torvalds WEAK(miata_mv);
1911da177e4SLinus Torvalds WEAK(mikasa_mv);
1921da177e4SLinus Torvalds WEAK(mikasa_primo_mv);
1931da177e4SLinus Torvalds WEAK(monet_mv);
1941da177e4SLinus Torvalds WEAK(nautilus_mv);
1951da177e4SLinus Torvalds WEAK(noname_mv);
1961da177e4SLinus Torvalds WEAK(noritake_mv);
1971da177e4SLinus Torvalds WEAK(noritake_primo_mv);
1981da177e4SLinus Torvalds WEAK(p2k_mv);
1991da177e4SLinus Torvalds WEAK(pc164_mv);
2001da177e4SLinus Torvalds WEAK(privateer_mv);
2011da177e4SLinus Torvalds WEAK(rawhide_mv);
2021da177e4SLinus Torvalds WEAK(ruffian_mv);
2031da177e4SLinus Torvalds WEAK(rx164_mv);
2041da177e4SLinus Torvalds WEAK(sable_mv);
2051da177e4SLinus Torvalds WEAK(sable_gamma_mv);
2061da177e4SLinus Torvalds WEAK(shark_mv);
2071da177e4SLinus Torvalds WEAK(sx164_mv);
2081da177e4SLinus Torvalds WEAK(takara_mv);
2091da177e4SLinus Torvalds WEAK(titan_mv);
2101da177e4SLinus Torvalds WEAK(webbrick_mv);
2111da177e4SLinus Torvalds WEAK(wildfire_mv);
2121da177e4SLinus Torvalds WEAK(xl_mv);
2131da177e4SLinus Torvalds WEAK(xlt_mv);
2141da177e4SLinus Torvalds
2151da177e4SLinus Torvalds #undef WEAK
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds /*
2181da177e4SLinus Torvalds * I/O resources inherited from PeeCees. Except for perhaps the
2191da177e4SLinus Torvalds * turbochannel alphas, everyone has these on some sort of SuperIO chip.
2201da177e4SLinus Torvalds *
2211da177e4SLinus Torvalds * ??? If this becomes less standard, move the struct out into the
2221da177e4SLinus Torvalds * machine vector.
2231da177e4SLinus Torvalds */
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds static void __init
reserve_std_resources(void)2261da177e4SLinus Torvalds reserve_std_resources(void)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds static struct resource standard_io_resources[] = {
2291da177e4SLinus Torvalds { .name = "rtc", .start = -1, .end = -1 },
2301da177e4SLinus Torvalds { .name = "dma1", .start = 0x00, .end = 0x1f },
2311da177e4SLinus Torvalds { .name = "pic1", .start = 0x20, .end = 0x3f },
2321da177e4SLinus Torvalds { .name = "timer", .start = 0x40, .end = 0x5f },
2331da177e4SLinus Torvalds { .name = "keyboard", .start = 0x60, .end = 0x6f },
2341da177e4SLinus Torvalds { .name = "dma page reg", .start = 0x80, .end = 0x8f },
2351da177e4SLinus Torvalds { .name = "pic2", .start = 0xa0, .end = 0xbf },
2361da177e4SLinus Torvalds { .name = "dma2", .start = 0xc0, .end = 0xdf },
2371da177e4SLinus Torvalds };
2381da177e4SLinus Torvalds
2391da177e4SLinus Torvalds struct resource *io = &ioport_resource;
2401da177e4SLinus Torvalds size_t i;
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds if (hose_head) {
2431da177e4SLinus Torvalds struct pci_controller *hose;
2441da177e4SLinus Torvalds for (hose = hose_head; hose; hose = hose->next)
2451da177e4SLinus Torvalds if (hose->index == 0) {
2461da177e4SLinus Torvalds io = hose->io_space;
2471da177e4SLinus Torvalds break;
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds /* Fix up for the Jensen's queer RTC placement. */
2521da177e4SLinus Torvalds standard_io_resources[0].start = RTC_PORT(0);
2535bea3044SMikulas Patocka standard_io_resources[0].end = RTC_PORT(0) + 0x0f;
2541da177e4SLinus Torvalds
25525c8716cSTobias Klauser for (i = 0; i < ARRAY_SIZE(standard_io_resources); ++i)
2561da177e4SLinus Torvalds request_resource(io, standard_io_resources+i);
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds #define PFN_MAX PFN_DOWN(0x80000000)
260fb26b3e6SRoel Kluin #define for_each_mem_cluster(memdesc, _cluster, i) \
261fb26b3e6SRoel Kluin for ((_cluster) = (memdesc)->cluster, (i) = 0; \
262fb26b3e6SRoel Kluin (i) < (memdesc)->numclusters; (i)++, (_cluster)++)
2631da177e4SLinus Torvalds
2641da177e4SLinus Torvalds static unsigned long __init
get_mem_size_limit(char * s)2651da177e4SLinus Torvalds get_mem_size_limit(char *s)
2661da177e4SLinus Torvalds {
2671da177e4SLinus Torvalds unsigned long end = 0;
2681da177e4SLinus Torvalds char *from = s;
2691da177e4SLinus Torvalds
2701da177e4SLinus Torvalds end = simple_strtoul(from, &from, 0);
2711da177e4SLinus Torvalds if ( *from == 'K' || *from == 'k' ) {
2721da177e4SLinus Torvalds end = end << 10;
2731da177e4SLinus Torvalds from++;
2741da177e4SLinus Torvalds } else if ( *from == 'M' || *from == 'm' ) {
2751da177e4SLinus Torvalds end = end << 20;
2761da177e4SLinus Torvalds from++;
2771da177e4SLinus Torvalds } else if ( *from == 'G' || *from == 'g' ) {
2781da177e4SLinus Torvalds end = end << 30;
2791da177e4SLinus Torvalds from++;
2801da177e4SLinus Torvalds }
2811da177e4SLinus Torvalds return end >> PAGE_SHIFT; /* Return the PFN of the limit. */
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds
2841da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_INITRD
2851da177e4SLinus Torvalds void * __init
move_initrd(unsigned long mem_limit)2861da177e4SLinus Torvalds move_initrd(unsigned long mem_limit)
2871da177e4SLinus Torvalds {
2881da177e4SLinus Torvalds void *start;
2891da177e4SLinus Torvalds unsigned long size;
2901da177e4SLinus Torvalds
2911da177e4SLinus Torvalds size = initrd_end - initrd_start;
2929415673eSMike Rapoport start = memblock_alloc(PAGE_ALIGN(size), PAGE_SIZE);
2931da177e4SLinus Torvalds if (!start || __pa(start) + size > mem_limit) {
2941da177e4SLinus Torvalds initrd_start = initrd_end = 0;
2951da177e4SLinus Torvalds return NULL;
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds memmove(start, (void *)initrd_start, size);
2981da177e4SLinus Torvalds initrd_start = (unsigned long)start;
2991da177e4SLinus Torvalds initrd_end = initrd_start + size;
3001da177e4SLinus Torvalds printk("initrd moved to %p\n", start);
3011da177e4SLinus Torvalds return start;
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds #endif
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds static void __init
setup_memory(void * kernel_end)3061da177e4SLinus Torvalds setup_memory(void *kernel_end)
3071da177e4SLinus Torvalds {
3081da177e4SLinus Torvalds struct memclust_struct * cluster;
3091da177e4SLinus Torvalds struct memdesc_struct * memdesc;
3106471f52aSMike Rapoport unsigned long kernel_size;
3111da177e4SLinus Torvalds unsigned long i;
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds /* Find free clusters, and init and free the bootmem accordingly. */
3141da177e4SLinus Torvalds memdesc = (struct memdesc_struct *)
3151da177e4SLinus Torvalds (hwrpb->mddt_offset + (unsigned long) hwrpb);
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds for_each_mem_cluster(memdesc, cluster, i) {
3186471f52aSMike Rapoport unsigned long end;
3196471f52aSMike Rapoport
3201da177e4SLinus Torvalds printk("memcluster %lu, usage %01lx, start %8lu, end %8lu\n",
3211da177e4SLinus Torvalds i, cluster->usage, cluster->start_pfn,
3221da177e4SLinus Torvalds cluster->start_pfn + cluster->numpages);
3231da177e4SLinus Torvalds
3241da177e4SLinus Torvalds end = cluster->start_pfn + cluster->numpages;
3251da177e4SLinus Torvalds if (end > max_low_pfn)
3261da177e4SLinus Torvalds max_low_pfn = end;
3276471f52aSMike Rapoport
3286471f52aSMike Rapoport memblock_add(PFN_PHYS(cluster->start_pfn),
3296471f52aSMike Rapoport cluster->numpages << PAGE_SHIFT);
330640b7ea5SMike Rapoport
331640b7ea5SMike Rapoport /* Bit 0 is console/PALcode reserved. Bit 1 is
332640b7ea5SMike Rapoport non-volatile memory -- we might want to mark
333640b7ea5SMike Rapoport this for later. */
334640b7ea5SMike Rapoport if (cluster->usage & 3)
335640b7ea5SMike Rapoport memblock_reserve(PFN_PHYS(cluster->start_pfn),
336640b7ea5SMike Rapoport cluster->numpages << PAGE_SHIFT);
3371da177e4SLinus Torvalds }
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds /*
3401da177e4SLinus Torvalds * Except for the NUMA systems (wildfire, marvel) all of the
3411da177e4SLinus Torvalds * Alpha systems we run on support 32GB of memory or less.
3421da177e4SLinus Torvalds * Since the NUMA systems introduce large holes in memory addressing,
3431da177e4SLinus Torvalds * we can get into a situation where there is not enough contiguous
3441da177e4SLinus Torvalds * memory for the memory map.
3451da177e4SLinus Torvalds *
3461da177e4SLinus Torvalds * Limit memory to the first 32GB to limit the NUMA systems to
3471da177e4SLinus Torvalds * memory on their first node (wildfire) or 2 (marvel) to avoid
3481da177e4SLinus Torvalds * not being able to produce the memory map. In order to access
3491da177e4SLinus Torvalds * all of the memory on the NUMA systems, build with discontiguous
3501da177e4SLinus Torvalds * memory support.
3511da177e4SLinus Torvalds *
3521da177e4SLinus Torvalds * If the user specified a memory limit, let that memory limit stand.
3531da177e4SLinus Torvalds */
3541da177e4SLinus Torvalds if (!mem_size_limit)
3551da177e4SLinus Torvalds mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT;
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds if (mem_size_limit && max_low_pfn >= mem_size_limit)
3581da177e4SLinus Torvalds {
3591da177e4SLinus Torvalds printk("setup: forcing memory size to %ldK (from %ldK).\n",
3601da177e4SLinus Torvalds mem_size_limit << (PAGE_SHIFT - 10),
3611da177e4SLinus Torvalds max_low_pfn << (PAGE_SHIFT - 10));
3621da177e4SLinus Torvalds max_low_pfn = mem_size_limit;
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds
3656471f52aSMike Rapoport /* Reserve the kernel memory. */
3666471f52aSMike Rapoport kernel_size = virt_to_phys(kernel_end) - KERNEL_START_PHYS;
3676471f52aSMike Rapoport memblock_reserve(KERNEL_START_PHYS, kernel_size);
3681da177e4SLinus Torvalds
3691da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_INITRD
3701da177e4SLinus Torvalds initrd_start = INITRD_START;
3711da177e4SLinus Torvalds if (initrd_start) {
3721da177e4SLinus Torvalds initrd_end = initrd_start+INITRD_SIZE;
3731da177e4SLinus Torvalds printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
3741da177e4SLinus Torvalds (void *) initrd_start, INITRD_SIZE);
3751da177e4SLinus Torvalds
3761da177e4SLinus Torvalds if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
3771da177e4SLinus Torvalds if (!move_initrd(PFN_PHYS(max_low_pfn)))
3781da177e4SLinus Torvalds printk("initrd extends beyond end of memory "
3791da177e4SLinus Torvalds "(0x%08lx > 0x%p)\ndisabling initrd\n",
3801da177e4SLinus Torvalds initrd_end,
3811da177e4SLinus Torvalds phys_to_virt(PFN_PHYS(max_low_pfn)));
3821da177e4SLinus Torvalds } else {
3836471f52aSMike Rapoport memblock_reserve(virt_to_phys((void *)initrd_start),
3846471f52aSMike Rapoport INITRD_SIZE);
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds }
3871da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_INITRD */
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds
page_is_ram(unsigned long pfn)3906ccbd7fdSMasahiro Yamada int page_is_ram(unsigned long pfn)
3911da177e4SLinus Torvalds {
3921da177e4SLinus Torvalds struct memclust_struct * cluster;
3931da177e4SLinus Torvalds struct memdesc_struct * memdesc;
3941da177e4SLinus Torvalds unsigned long i;
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds memdesc = (struct memdesc_struct *)
3971da177e4SLinus Torvalds (hwrpb->mddt_offset + (unsigned long) hwrpb);
3981da177e4SLinus Torvalds for_each_mem_cluster(memdesc, cluster, i)
3991da177e4SLinus Torvalds {
4001da177e4SLinus Torvalds if (pfn >= cluster->start_pfn &&
4011da177e4SLinus Torvalds pfn < cluster->start_pfn + cluster->numpages) {
4021da177e4SLinus Torvalds return (cluster->usage & 3) ? 0 : 1;
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds return 0;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds
409917b1f78SBrian Uhrain says static int __init
register_cpus(void)410917b1f78SBrian Uhrain says register_cpus(void)
411917b1f78SBrian Uhrain says {
412917b1f78SBrian Uhrain says int i;
413917b1f78SBrian Uhrain says
414917b1f78SBrian Uhrain says for_each_possible_cpu(i) {
415917b1f78SBrian Uhrain says struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
416917b1f78SBrian Uhrain says if (!p)
417917b1f78SBrian Uhrain says return -ENOMEM;
41876b67ed9SKAMEZAWA Hiroyuki register_cpu(p, i);
419917b1f78SBrian Uhrain says }
420917b1f78SBrian Uhrain says return 0;
421917b1f78SBrian Uhrain says }
422917b1f78SBrian Uhrain says
423917b1f78SBrian Uhrain says arch_initcall(register_cpus);
424917b1f78SBrian Uhrain says
4250f1c9688SEmil Velikov #ifdef CONFIG_MAGIC_SYSRQ
sysrq_reboot_handler(u8 unused)426bcb48185SJiri Slaby static void sysrq_reboot_handler(u8 unused)
427777747f6SJoerg Roedel {
428777747f6SJoerg Roedel machine_halt();
429777747f6SJoerg Roedel }
430777747f6SJoerg Roedel
431f95850ecSEmil Velikov static const struct sysrq_key_op srm_sysrq_reboot_op = {
432777747f6SJoerg Roedel .handler = sysrq_reboot_handler,
4330f1c9688SEmil Velikov .help_msg = "reboot(b)",
4340f1c9688SEmil Velikov .action_msg = "Resetting",
4350f1c9688SEmil Velikov .enable_mask = SYSRQ_ENABLE_BOOT,
4360f1c9688SEmil Velikov };
4370f1c9688SEmil Velikov #endif
4380f1c9688SEmil Velikov
4391da177e4SLinus Torvalds void __init
setup_arch(char ** cmdline_p)4401da177e4SLinus Torvalds setup_arch(char **cmdline_p)
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds extern char _end[];
4431da177e4SLinus Torvalds
4441da177e4SLinus Torvalds struct alpha_machine_vector *vec = NULL;
4451da177e4SLinus Torvalds struct percpu_struct *cpu;
4461da177e4SLinus Torvalds char *type_name, *var_name, *p;
4471da177e4SLinus Torvalds void *kernel_end = _end; /* end of kernel */
4481da177e4SLinus Torvalds char *args = command_line;
4491da177e4SLinus Torvalds
4501da177e4SLinus Torvalds hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
4511da177e4SLinus Torvalds boot_cpuid = hard_smp_processor_id();
4521da177e4SLinus Torvalds
4531da177e4SLinus Torvalds /*
4541da177e4SLinus Torvalds * Pre-process the system type to make sure it will be valid.
4551da177e4SLinus Torvalds *
4561da177e4SLinus Torvalds * This may restore real CABRIO and EB66+ family names, ie
4571da177e4SLinus Torvalds * EB64+ and EB66.
4581da177e4SLinus Torvalds *
4591da177e4SLinus Torvalds * Oh, and "white box" AS800 (aka DIGITAL Server 3000 series)
4601da177e4SLinus Torvalds * and AS1200 (DIGITAL Server 5000 series) have the type as
4611da177e4SLinus Torvalds * the negative of the real one.
4621da177e4SLinus Torvalds */
4631da177e4SLinus Torvalds if ((long)hwrpb->sys_type < 0) {
4641da177e4SLinus Torvalds hwrpb->sys_type = -((long)hwrpb->sys_type);
4651da177e4SLinus Torvalds hwrpb_update_checksum(hwrpb);
4661da177e4SLinus Torvalds }
4671da177e4SLinus Torvalds
4681da177e4SLinus Torvalds /* Register a call for panic conditions. */
469e041c683SAlan Stern atomic_notifier_chain_register(&panic_notifier_list,
470e041c683SAlan Stern &alpha_panic_block);
4711da177e4SLinus Torvalds
472994dcf70SRichard Henderson #ifndef alpha_using_srm
4731da177e4SLinus Torvalds /* Assume that we've booted from SRM if we haven't booted from MILO.
4741da177e4SLinus Torvalds Detect the later by looking for "MILO" in the system serial nr. */
4755f14596eSChuhong Yuan alpha_using_srm = !str_has_prefix((const char *)hwrpb->ssn, "MILO");
4761da177e4SLinus Torvalds #endif
477994dcf70SRichard Henderson #ifndef alpha_using_qemu
478994dcf70SRichard Henderson /* Similarly, look for QEMU. */
479994dcf70SRichard Henderson alpha_using_qemu = strstr((const char *)hwrpb->ssn, "QEMU") != 0;
480994dcf70SRichard Henderson #endif
4811da177e4SLinus Torvalds
4821da177e4SLinus Torvalds /* If we are using SRM, we want to allow callbacks
4831da177e4SLinus Torvalds as early as possible, so do this NOW, and then
4841da177e4SLinus Torvalds they should work immediately thereafter.
4851da177e4SLinus Torvalds */
4861da177e4SLinus Torvalds kernel_end = callback_init(kernel_end);
4871da177e4SLinus Torvalds
4881da177e4SLinus Torvalds /*
4891da177e4SLinus Torvalds * Locate the command line.
4901da177e4SLinus Torvalds */
4911da177e4SLinus Torvalds /* Hack for Jensen... since we're restricted to 8 or 16 chars for
4921da177e4SLinus Torvalds boot flags depending on the boot mode, we need some shorthand.
4931da177e4SLinus Torvalds This should do for installation. */
4941da177e4SLinus Torvalds if (strcmp(COMMAND_LINE, "INSTALL") == 0) {
49588040e67SWolfram Sang strscpy(command_line, "root=/dev/fd0 load_ramdisk=1", sizeof(command_line));
4961da177e4SLinus Torvalds } else {
49788040e67SWolfram Sang strscpy(command_line, COMMAND_LINE, sizeof(command_line));
4981da177e4SLinus Torvalds }
4993c253ca0SAlon Bar-Lev strcpy(boot_command_line, command_line);
5001da177e4SLinus Torvalds *cmdline_p = command_line;
5011da177e4SLinus Torvalds
5021da177e4SLinus Torvalds /*
5031da177e4SLinus Torvalds * Process command-line arguments.
5041da177e4SLinus Torvalds */
5051da177e4SLinus Torvalds while ((p = strsep(&args, " \t")) != NULL) {
5061da177e4SLinus Torvalds if (!*p) continue;
5071da177e4SLinus Torvalds if (strncmp(p, "alpha_mv=", 9) == 0) {
5081da177e4SLinus Torvalds vec = get_sysvec_byname(p+9);
5091da177e4SLinus Torvalds continue;
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds if (strncmp(p, "cycle=", 6) == 0) {
5121da177e4SLinus Torvalds est_cycle_freq = simple_strtol(p+6, NULL, 0);
5131da177e4SLinus Torvalds continue;
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds if (strncmp(p, "mem=", 4) == 0) {
5161da177e4SLinus Torvalds mem_size_limit = get_mem_size_limit(p+4);
5171da177e4SLinus Torvalds continue;
5181da177e4SLinus Torvalds }
5191da177e4SLinus Torvalds if (strncmp(p, "srmcons", 7) == 0) {
5201da177e4SLinus Torvalds srmcons_output |= 1;
5211da177e4SLinus Torvalds continue;
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds if (strncmp(p, "console=srm", 11) == 0) {
5241da177e4SLinus Torvalds srmcons_output |= 2;
5251da177e4SLinus Torvalds continue;
5261da177e4SLinus Torvalds }
5271da177e4SLinus Torvalds if (strncmp(p, "gartsize=", 9) == 0) {
5281da177e4SLinus Torvalds alpha_agpgart_size =
5291da177e4SLinus Torvalds get_mem_size_limit(p+9) << PAGE_SHIFT;
5301da177e4SLinus Torvalds continue;
5311da177e4SLinus Torvalds }
5321da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
5331da177e4SLinus Torvalds if (strncmp(p, "verbose_mcheck=", 15) == 0) {
5341da177e4SLinus Torvalds alpha_verbose_mcheck = simple_strtol(p+15, NULL, 0);
5351da177e4SLinus Torvalds continue;
5361da177e4SLinus Torvalds }
5371da177e4SLinus Torvalds #endif
5381da177e4SLinus Torvalds }
5391da177e4SLinus Torvalds
5401da177e4SLinus Torvalds /* Replace the command line, now that we've killed it with strsep. */
5413c253ca0SAlon Bar-Lev strcpy(command_line, boot_command_line);
5421da177e4SLinus Torvalds
5431da177e4SLinus Torvalds /* If we want SRM console printk echoing early, do it now. */
5441da177e4SLinus Torvalds if (alpha_using_srm && srmcons_output) {
5451da177e4SLinus Torvalds register_srm_console();
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds /*
5481da177e4SLinus Torvalds * If "console=srm" was specified, clear the srmcons_output
5491da177e4SLinus Torvalds * flag now so that time.c won't unregister_srm_console
5501da177e4SLinus Torvalds */
5511da177e4SLinus Torvalds if (srmcons_output & 2)
5521da177e4SLinus Torvalds srmcons_output = 0;
5531da177e4SLinus Torvalds }
5541da177e4SLinus Torvalds
5551da177e4SLinus Torvalds #ifdef CONFIG_MAGIC_SYSRQ
5561da177e4SLinus Torvalds /* If we're using SRM, make sysrq-b halt back to the prom,
5571da177e4SLinus Torvalds not auto-reboot. */
5581da177e4SLinus Torvalds if (alpha_using_srm) {
5590f1c9688SEmil Velikov unregister_sysrq_key('b', __sysrq_reboot_op);
5600f1c9688SEmil Velikov register_sysrq_key('b', &srm_sysrq_reboot_op);
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds #endif
5631da177e4SLinus Torvalds
5641da177e4SLinus Torvalds /*
5651da177e4SLinus Torvalds * Identify and reconfigure for the current system.
5661da177e4SLinus Torvalds */
5671da177e4SLinus Torvalds cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
5681da177e4SLinus Torvalds
5691da177e4SLinus Torvalds get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
5701da177e4SLinus Torvalds cpu->type, &type_name, &var_name);
5711da177e4SLinus Torvalds if (*var_name == '0')
5721da177e4SLinus Torvalds var_name = "";
5731da177e4SLinus Torvalds
5741da177e4SLinus Torvalds if (!vec) {
5751da177e4SLinus Torvalds vec = get_sysvec(hwrpb->sys_type, hwrpb->sys_variation,
5761da177e4SLinus Torvalds cpu->type);
5771da177e4SLinus Torvalds }
5781da177e4SLinus Torvalds
5791da177e4SLinus Torvalds if (!vec) {
5801da177e4SLinus Torvalds panic("Unsupported system type: %s%s%s (%ld %ld)\n",
5811da177e4SLinus Torvalds type_name, (*var_name ? " variation " : ""), var_name,
5821da177e4SLinus Torvalds hwrpb->sys_type, hwrpb->sys_variation);
5831da177e4SLinus Torvalds }
5841da177e4SLinus Torvalds if (vec != &alpha_mv) {
5851da177e4SLinus Torvalds alpha_mv = *vec;
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds
5881da177e4SLinus Torvalds printk("Booting "
5891da177e4SLinus Torvalds #ifdef CONFIG_ALPHA_GENERIC
5901da177e4SLinus Torvalds "GENERIC "
5911da177e4SLinus Torvalds #endif
5921da177e4SLinus Torvalds "on %s%s%s using machine vector %s from %s\n",
5931da177e4SLinus Torvalds type_name, (*var_name ? " variation " : ""),
5941da177e4SLinus Torvalds var_name, alpha_mv.vector_name,
5951da177e4SLinus Torvalds (alpha_using_srm ? "SRM" : "MILO"));
5961da177e4SLinus Torvalds
5971da177e4SLinus Torvalds printk("Major Options: "
5981da177e4SLinus Torvalds #ifdef CONFIG_SMP
5991da177e4SLinus Torvalds "SMP "
6001da177e4SLinus Torvalds #endif
6011da177e4SLinus Torvalds #ifdef CONFIG_ALPHA_EV56
6021da177e4SLinus Torvalds "EV56 "
6031da177e4SLinus Torvalds #endif
6041da177e4SLinus Torvalds #ifdef CONFIG_ALPHA_EV67
6051da177e4SLinus Torvalds "EV67 "
6061da177e4SLinus Torvalds #endif
6071da177e4SLinus Torvalds #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
6081da177e4SLinus Torvalds "LEGACY_START "
6091da177e4SLinus Torvalds #endif
6101da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
6111da177e4SLinus Torvalds "VERBOSE_MCHECK "
6121da177e4SLinus Torvalds #endif
6131da177e4SLinus Torvalds
6141da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_SPINLOCK
6151da177e4SLinus Torvalds "DEBUG_SPINLOCK "
6161da177e4SLinus Torvalds #endif
6171da177e4SLinus Torvalds #ifdef CONFIG_MAGIC_SYSRQ
6181da177e4SLinus Torvalds "MAGIC_SYSRQ "
6191da177e4SLinus Torvalds #endif
6201da177e4SLinus Torvalds "\n");
6211da177e4SLinus Torvalds
6221da177e4SLinus Torvalds printk("Command line: %s\n", command_line);
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds /*
6251da177e4SLinus Torvalds * Sync up the HAE.
6261da177e4SLinus Torvalds * Save the SRM's current value for restoration.
6271da177e4SLinus Torvalds */
6281da177e4SLinus Torvalds srm_hae = *alpha_mv.hae_register;
6291da177e4SLinus Torvalds __set_hae(alpha_mv.hae_cache);
6301da177e4SLinus Torvalds
6311da177e4SLinus Torvalds /* Reset enable correctable error reports. */
6321da177e4SLinus Torvalds wrmces(0x7);
6331da177e4SLinus Torvalds
6341da177e4SLinus Torvalds /* Find our memory. */
6351da177e4SLinus Torvalds setup_memory(kernel_end);
6365b526090SMike Rapoport memblock_set_bottom_up(true);
63736d40290SMike Rapoport sparse_init();
6381da177e4SLinus Torvalds
6391da177e4SLinus Torvalds /* First guess at cpu cache sizes. Do this before init_arch. */
6401da177e4SLinus Torvalds determine_cpu_caches(cpu->type);
6411da177e4SLinus Torvalds
6421da177e4SLinus Torvalds /* Initialize the machine. Usually has to do with setting up
6431da177e4SLinus Torvalds DMA windows and the like. */
6441da177e4SLinus Torvalds if (alpha_mv.init_arch)
6451da177e4SLinus Torvalds alpha_mv.init_arch();
6461da177e4SLinus Torvalds
6471da177e4SLinus Torvalds /* Reserve standard resources. */
6481da177e4SLinus Torvalds reserve_std_resources();
6491da177e4SLinus Torvalds
6501da177e4SLinus Torvalds /*
6511da177e4SLinus Torvalds * Give us a default console. TGA users will see nothing until
6521da177e4SLinus Torvalds * chr_dev_init is called, rather late in the boot sequence.
6531da177e4SLinus Torvalds */
6541da177e4SLinus Torvalds
6551da177e4SLinus Torvalds #ifdef CONFIG_VT
6561da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
6571da177e4SLinus Torvalds conswitchp = &vga_con;
6581da177e4SLinus Torvalds #endif
6591da177e4SLinus Torvalds #endif
6601da177e4SLinus Torvalds
6611da177e4SLinus Torvalds /* Default root filesystem to sda2. */
662f5524c3fSChristoph Hellwig ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 2);
6631da177e4SLinus Torvalds
6641da177e4SLinus Torvalds #ifdef CONFIG_EISA
6651da177e4SLinus Torvalds /* FIXME: only set this when we actually have EISA in this box? */
6661da177e4SLinus Torvalds EISA_bus = 1;
6671da177e4SLinus Torvalds #endif
6681da177e4SLinus Torvalds
6691da177e4SLinus Torvalds /*
6701da177e4SLinus Torvalds * Check ASN in HWRPB for validity, report if bad.
6711da177e4SLinus Torvalds * FIXME: how was this failing? Should we trust it instead,
6721da177e4SLinus Torvalds * and copy the value into alpha_mv.max_asn?
6731da177e4SLinus Torvalds */
6741da177e4SLinus Torvalds
6751da177e4SLinus Torvalds if (hwrpb->max_asn != MAX_ASN) {
6761da177e4SLinus Torvalds printk("Max ASN from HWRPB is bad (0x%lx)\n", hwrpb->max_asn);
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds
6791da177e4SLinus Torvalds /*
6801da177e4SLinus Torvalds * Identify the flock of penguins.
6811da177e4SLinus Torvalds */
6821da177e4SLinus Torvalds
6831da177e4SLinus Torvalds #ifdef CONFIG_SMP
6841da177e4SLinus Torvalds setup_smp();
6851da177e4SLinus Torvalds #endif
6861da177e4SLinus Torvalds paging_init();
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds
6891da177e4SLinus Torvalds static char sys_unknown[] = "Unknown";
6901da177e4SLinus Torvalds static char systype_names[][16] = {
6911da177e4SLinus Torvalds "0",
6921da177e4SLinus Torvalds "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen",
6931da177e4SLinus Torvalds "Pelican", "Morgan", "Sable", "Medulla", "Noname",
6941da177e4SLinus Torvalds "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind",
6951da177e4SLinus Torvalds "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
6961da177e4SLinus Torvalds "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
6971da177e4SLinus Torvalds "Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
6981da177e4SLinus Torvalds "Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan", "Marvel"
6991da177e4SLinus Torvalds };
7001da177e4SLinus Torvalds
7011da177e4SLinus Torvalds static char unofficial_names[][8] = {"100", "Ruffian"};
7021da177e4SLinus Torvalds
7031da177e4SLinus Torvalds static char api_names[][16] = {"200", "Nautilus"};
7041da177e4SLinus Torvalds
7051da177e4SLinus Torvalds static char eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164", "RX164"};
7061da177e4SLinus Torvalds static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,4};
7071da177e4SLinus Torvalds
7081da177e4SLinus Torvalds static char alcor_names[][16] = {"Alcor", "Maverick", "Bret"};
7091da177e4SLinus Torvalds static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds static char eb64p_names[][16] = {"EB64+", "Cabriolet", "AlphaPCI64"};
7121da177e4SLinus Torvalds static int eb64p_indices[] = {0,0,1,2};
7131da177e4SLinus Torvalds
7141da177e4SLinus Torvalds static char eb66_names[][8] = {"EB66", "EB66+"};
7151da177e4SLinus Torvalds static int eb66_indices[] = {0,0,1};
7161da177e4SLinus Torvalds
7171da177e4SLinus Torvalds static char marvel_names[][16] = {
7181da177e4SLinus Torvalds "Marvel/EV7"
7191da177e4SLinus Torvalds };
7201da177e4SLinus Torvalds static int marvel_indices[] = { 0 };
7211da177e4SLinus Torvalds
7221da177e4SLinus Torvalds static char rawhide_names[][16] = {
7231da177e4SLinus Torvalds "Dodge", "Wrangler", "Durango", "Tincup", "DaVinci"
7241da177e4SLinus Torvalds };
7251da177e4SLinus Torvalds static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
7261da177e4SLinus Torvalds
7271da177e4SLinus Torvalds static char titan_names[][16] = {
7281da177e4SLinus Torvalds "DEFAULT", "Privateer", "Falcon", "Granite"
7291da177e4SLinus Torvalds };
7301da177e4SLinus Torvalds static int titan_indices[] = {0,1,2,2,3};
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds static char tsunami_names[][16] = {
7331da177e4SLinus Torvalds "0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper",
7341da177e4SLinus Torvalds "Goldrush", "Webbrick", "Catamaran", "Brisbane", "Melbourne",
7351da177e4SLinus Torvalds "Flying Clipper", "Shark"
7361da177e4SLinus Torvalds };
7371da177e4SLinus Torvalds static int tsunami_indices[] = {0,1,2,3,4,5,6,7,8,9,10,11,12};
7381da177e4SLinus Torvalds
7391da177e4SLinus Torvalds static struct alpha_machine_vector * __init
get_sysvec(unsigned long type,unsigned long variation,unsigned long cpu)7401da177e4SLinus Torvalds get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
7411da177e4SLinus Torvalds {
7421da177e4SLinus Torvalds static struct alpha_machine_vector *systype_vecs[] __initdata =
7431da177e4SLinus Torvalds {
7441da177e4SLinus Torvalds NULL, /* 0 */
7451da177e4SLinus Torvalds NULL, /* ADU */
7461da177e4SLinus Torvalds NULL, /* Cobra */
7471da177e4SLinus Torvalds NULL, /* Ruby */
7481da177e4SLinus Torvalds NULL, /* Flamingo */
7491da177e4SLinus Torvalds NULL, /* Mannequin */
7501da177e4SLinus Torvalds &jensen_mv,
7511da177e4SLinus Torvalds NULL, /* Pelican */
7521da177e4SLinus Torvalds NULL, /* Morgan */
7531da177e4SLinus Torvalds NULL, /* Sable -- see below. */
7541da177e4SLinus Torvalds NULL, /* Medulla */
7551da177e4SLinus Torvalds &noname_mv,
7561da177e4SLinus Torvalds NULL, /* Turbolaser */
7571da177e4SLinus Torvalds &avanti_mv,
7581da177e4SLinus Torvalds NULL, /* Mustang */
7591da177e4SLinus Torvalds NULL, /* Alcor, Bret, Maverick. HWRPB inaccurate? */
7601da177e4SLinus Torvalds NULL, /* Tradewind */
7611da177e4SLinus Torvalds NULL, /* Mikasa -- see below. */
7621da177e4SLinus Torvalds NULL, /* EB64 */
7631da177e4SLinus Torvalds NULL, /* EB66 -- see variation. */
7641da177e4SLinus Torvalds NULL, /* EB64+ -- see variation. */
7651da177e4SLinus Torvalds &alphabook1_mv,
7661da177e4SLinus Torvalds &rawhide_mv,
7671da177e4SLinus Torvalds NULL, /* K2 */
7681da177e4SLinus Torvalds &lynx_mv, /* Lynx */
7691da177e4SLinus Torvalds &xl_mv,
7701da177e4SLinus Torvalds NULL, /* EB164 -- see variation. */
7711da177e4SLinus Torvalds NULL, /* Noritake -- see below. */
7721da177e4SLinus Torvalds NULL, /* Cortex */
7731da177e4SLinus Torvalds NULL, /* 29 */
7741da177e4SLinus Torvalds &miata_mv,
7751da177e4SLinus Torvalds NULL, /* XXM */
7761da177e4SLinus Torvalds &takara_mv,
7771da177e4SLinus Torvalds NULL, /* Yukon */
7781da177e4SLinus Torvalds NULL, /* Tsunami -- see variation. */
7791da177e4SLinus Torvalds &wildfire_mv, /* Wildfire */
7801da177e4SLinus Torvalds NULL, /* CUSCO */
7811da177e4SLinus Torvalds &eiger_mv, /* Eiger */
7821da177e4SLinus Torvalds NULL, /* Titan */
7831da177e4SLinus Torvalds NULL, /* Marvel */
7841da177e4SLinus Torvalds };
7851da177e4SLinus Torvalds
7861da177e4SLinus Torvalds static struct alpha_machine_vector *unofficial_vecs[] __initdata =
7871da177e4SLinus Torvalds {
7881da177e4SLinus Torvalds NULL, /* 100 */
7891da177e4SLinus Torvalds &ruffian_mv,
7901da177e4SLinus Torvalds };
7911da177e4SLinus Torvalds
7921da177e4SLinus Torvalds static struct alpha_machine_vector *api_vecs[] __initdata =
7931da177e4SLinus Torvalds {
7941da177e4SLinus Torvalds NULL, /* 200 */
7951da177e4SLinus Torvalds &nautilus_mv,
7961da177e4SLinus Torvalds };
7971da177e4SLinus Torvalds
7981da177e4SLinus Torvalds static struct alpha_machine_vector *alcor_vecs[] __initdata =
7991da177e4SLinus Torvalds {
8001da177e4SLinus Torvalds &alcor_mv, &xlt_mv, &xlt_mv
8011da177e4SLinus Torvalds };
8021da177e4SLinus Torvalds
8031da177e4SLinus Torvalds static struct alpha_machine_vector *eb164_vecs[] __initdata =
8041da177e4SLinus Torvalds {
8051da177e4SLinus Torvalds &eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv, &rx164_mv
8061da177e4SLinus Torvalds };
8071da177e4SLinus Torvalds
8081da177e4SLinus Torvalds static struct alpha_machine_vector *eb64p_vecs[] __initdata =
8091da177e4SLinus Torvalds {
8101da177e4SLinus Torvalds &eb64p_mv,
8111da177e4SLinus Torvalds &cabriolet_mv,
8121da177e4SLinus Torvalds &cabriolet_mv /* AlphaPCI64 */
8131da177e4SLinus Torvalds };
8141da177e4SLinus Torvalds
8151da177e4SLinus Torvalds static struct alpha_machine_vector *eb66_vecs[] __initdata =
8161da177e4SLinus Torvalds {
8171da177e4SLinus Torvalds &eb66_mv,
8181da177e4SLinus Torvalds &eb66p_mv
8191da177e4SLinus Torvalds };
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvalds static struct alpha_machine_vector *marvel_vecs[] __initdata =
8221da177e4SLinus Torvalds {
8231da177e4SLinus Torvalds &marvel_ev7_mv,
8241da177e4SLinus Torvalds };
8251da177e4SLinus Torvalds
8261da177e4SLinus Torvalds static struct alpha_machine_vector *titan_vecs[] __initdata =
8271da177e4SLinus Torvalds {
8281da177e4SLinus Torvalds &titan_mv, /* default */
8291da177e4SLinus Torvalds &privateer_mv, /* privateer */
8301da177e4SLinus Torvalds &titan_mv, /* falcon */
8311da177e4SLinus Torvalds &privateer_mv, /* granite */
8321da177e4SLinus Torvalds };
8331da177e4SLinus Torvalds
8341da177e4SLinus Torvalds static struct alpha_machine_vector *tsunami_vecs[] __initdata =
8351da177e4SLinus Torvalds {
8361da177e4SLinus Torvalds NULL,
8371da177e4SLinus Torvalds &dp264_mv, /* dp264 */
8381da177e4SLinus Torvalds &dp264_mv, /* warhol */
8391da177e4SLinus Torvalds &dp264_mv, /* windjammer */
8401da177e4SLinus Torvalds &monet_mv, /* monet */
8411da177e4SLinus Torvalds &clipper_mv, /* clipper */
8421da177e4SLinus Torvalds &dp264_mv, /* goldrush */
8431da177e4SLinus Torvalds &webbrick_mv, /* webbrick */
8441da177e4SLinus Torvalds &dp264_mv, /* catamaran */
8451da177e4SLinus Torvalds NULL, /* brisbane? */
8461da177e4SLinus Torvalds NULL, /* melbourne? */
8471da177e4SLinus Torvalds NULL, /* flying clipper? */
8481da177e4SLinus Torvalds &shark_mv, /* shark */
8491da177e4SLinus Torvalds };
8501da177e4SLinus Torvalds
8511da177e4SLinus Torvalds /* ??? Do we need to distinguish between Rawhides? */
8521da177e4SLinus Torvalds
8531da177e4SLinus Torvalds struct alpha_machine_vector *vec;
8541da177e4SLinus Torvalds
8551da177e4SLinus Torvalds /* Search the system tables first... */
8561da177e4SLinus Torvalds vec = NULL;
85725c8716cSTobias Klauser if (type < ARRAY_SIZE(systype_vecs)) {
8581da177e4SLinus Torvalds vec = systype_vecs[type];
8591da177e4SLinus Torvalds } else if ((type > ST_API_BIAS) &&
86025c8716cSTobias Klauser (type - ST_API_BIAS) < ARRAY_SIZE(api_vecs)) {
8611da177e4SLinus Torvalds vec = api_vecs[type - ST_API_BIAS];
8621da177e4SLinus Torvalds } else if ((type > ST_UNOFFICIAL_BIAS) &&
86325c8716cSTobias Klauser (type - ST_UNOFFICIAL_BIAS) < ARRAY_SIZE(unofficial_vecs)) {
8641da177e4SLinus Torvalds vec = unofficial_vecs[type - ST_UNOFFICIAL_BIAS];
8651da177e4SLinus Torvalds }
8661da177e4SLinus Torvalds
8671da177e4SLinus Torvalds /* If we've not found one, try for a variation. */
8681da177e4SLinus Torvalds
8691da177e4SLinus Torvalds if (!vec) {
8701da177e4SLinus Torvalds /* Member ID is a bit-field. */
8711da177e4SLinus Torvalds unsigned long member = (variation >> 10) & 0x3f;
8721da177e4SLinus Torvalds
8731da177e4SLinus Torvalds cpu &= 0xffffffff; /* make it usable */
8741da177e4SLinus Torvalds
8751da177e4SLinus Torvalds switch (type) {
8761da177e4SLinus Torvalds case ST_DEC_ALCOR:
87725c8716cSTobias Klauser if (member < ARRAY_SIZE(alcor_indices))
8781da177e4SLinus Torvalds vec = alcor_vecs[alcor_indices[member]];
8791da177e4SLinus Torvalds break;
8801da177e4SLinus Torvalds case ST_DEC_EB164:
88125c8716cSTobias Klauser if (member < ARRAY_SIZE(eb164_indices))
8821da177e4SLinus Torvalds vec = eb164_vecs[eb164_indices[member]];
8831da177e4SLinus Torvalds /* PC164 may show as EB164 variation with EV56 CPU,
8841da177e4SLinus Torvalds but, since no true EB164 had anything but EV5... */
8851da177e4SLinus Torvalds if (vec == &eb164_mv && cpu == EV56_CPU)
8861da177e4SLinus Torvalds vec = &pc164_mv;
8871da177e4SLinus Torvalds break;
8881da177e4SLinus Torvalds case ST_DEC_EB64P:
88925c8716cSTobias Klauser if (member < ARRAY_SIZE(eb64p_indices))
8901da177e4SLinus Torvalds vec = eb64p_vecs[eb64p_indices[member]];
8911da177e4SLinus Torvalds break;
8921da177e4SLinus Torvalds case ST_DEC_EB66:
89325c8716cSTobias Klauser if (member < ARRAY_SIZE(eb66_indices))
8941da177e4SLinus Torvalds vec = eb66_vecs[eb66_indices[member]];
8951da177e4SLinus Torvalds break;
8961da177e4SLinus Torvalds case ST_DEC_MARVEL:
89725c8716cSTobias Klauser if (member < ARRAY_SIZE(marvel_indices))
8981da177e4SLinus Torvalds vec = marvel_vecs[marvel_indices[member]];
8991da177e4SLinus Torvalds break;
9001da177e4SLinus Torvalds case ST_DEC_TITAN:
9011da177e4SLinus Torvalds vec = titan_vecs[0]; /* default */
90225c8716cSTobias Klauser if (member < ARRAY_SIZE(titan_indices))
9031da177e4SLinus Torvalds vec = titan_vecs[titan_indices[member]];
9041da177e4SLinus Torvalds break;
9051da177e4SLinus Torvalds case ST_DEC_TSUNAMI:
90625c8716cSTobias Klauser if (member < ARRAY_SIZE(tsunami_indices))
9071da177e4SLinus Torvalds vec = tsunami_vecs[tsunami_indices[member]];
9081da177e4SLinus Torvalds break;
9091da177e4SLinus Torvalds case ST_DEC_1000:
9101da177e4SLinus Torvalds if (cpu == EV5_CPU || cpu == EV56_CPU)
9111da177e4SLinus Torvalds vec = &mikasa_primo_mv;
9121da177e4SLinus Torvalds else
9131da177e4SLinus Torvalds vec = &mikasa_mv;
9141da177e4SLinus Torvalds break;
9151da177e4SLinus Torvalds case ST_DEC_NORITAKE:
9161da177e4SLinus Torvalds if (cpu == EV5_CPU || cpu == EV56_CPU)
9171da177e4SLinus Torvalds vec = &noritake_primo_mv;
9181da177e4SLinus Torvalds else
9191da177e4SLinus Torvalds vec = &noritake_mv;
9201da177e4SLinus Torvalds break;
9211da177e4SLinus Torvalds case ST_DEC_2100_A500:
9221da177e4SLinus Torvalds if (cpu == EV5_CPU || cpu == EV56_CPU)
9231da177e4SLinus Torvalds vec = &sable_gamma_mv;
9241da177e4SLinus Torvalds else
9251da177e4SLinus Torvalds vec = &sable_mv;
9261da177e4SLinus Torvalds break;
9271da177e4SLinus Torvalds }
9281da177e4SLinus Torvalds }
9291da177e4SLinus Torvalds return vec;
9301da177e4SLinus Torvalds }
9311da177e4SLinus Torvalds
9321da177e4SLinus Torvalds static struct alpha_machine_vector * __init
get_sysvec_byname(const char * name)9331da177e4SLinus Torvalds get_sysvec_byname(const char *name)
9341da177e4SLinus Torvalds {
9351da177e4SLinus Torvalds static struct alpha_machine_vector *all_vecs[] __initdata =
9361da177e4SLinus Torvalds {
9371da177e4SLinus Torvalds &alcor_mv,
9381da177e4SLinus Torvalds &alphabook1_mv,
9391da177e4SLinus Torvalds &avanti_mv,
9401da177e4SLinus Torvalds &cabriolet_mv,
9411da177e4SLinus Torvalds &clipper_mv,
9421da177e4SLinus Torvalds &dp264_mv,
9431da177e4SLinus Torvalds &eb164_mv,
9441da177e4SLinus Torvalds &eb64p_mv,
9451da177e4SLinus Torvalds &eb66_mv,
9461da177e4SLinus Torvalds &eb66p_mv,
9471da177e4SLinus Torvalds &eiger_mv,
9481da177e4SLinus Torvalds &jensen_mv,
9491da177e4SLinus Torvalds &lx164_mv,
9501da177e4SLinus Torvalds &lynx_mv,
9511da177e4SLinus Torvalds &miata_mv,
9521da177e4SLinus Torvalds &mikasa_mv,
9531da177e4SLinus Torvalds &mikasa_primo_mv,
9541da177e4SLinus Torvalds &monet_mv,
9551da177e4SLinus Torvalds &nautilus_mv,
9561da177e4SLinus Torvalds &noname_mv,
9571da177e4SLinus Torvalds &noritake_mv,
9581da177e4SLinus Torvalds &noritake_primo_mv,
9591da177e4SLinus Torvalds &p2k_mv,
9601da177e4SLinus Torvalds &pc164_mv,
9611da177e4SLinus Torvalds &privateer_mv,
9621da177e4SLinus Torvalds &rawhide_mv,
9631da177e4SLinus Torvalds &ruffian_mv,
9641da177e4SLinus Torvalds &rx164_mv,
9651da177e4SLinus Torvalds &sable_mv,
9661da177e4SLinus Torvalds &sable_gamma_mv,
9671da177e4SLinus Torvalds &shark_mv,
9681da177e4SLinus Torvalds &sx164_mv,
9691da177e4SLinus Torvalds &takara_mv,
9701da177e4SLinus Torvalds &webbrick_mv,
9711da177e4SLinus Torvalds &wildfire_mv,
9721da177e4SLinus Torvalds &xl_mv,
9731da177e4SLinus Torvalds &xlt_mv
9741da177e4SLinus Torvalds };
9751da177e4SLinus Torvalds
9761da177e4SLinus Torvalds size_t i;
9771da177e4SLinus Torvalds
97825c8716cSTobias Klauser for (i = 0; i < ARRAY_SIZE(all_vecs); ++i) {
9791da177e4SLinus Torvalds struct alpha_machine_vector *mv = all_vecs[i];
9801da177e4SLinus Torvalds if (strcasecmp(mv->vector_name, name) == 0)
9811da177e4SLinus Torvalds return mv;
9821da177e4SLinus Torvalds }
9831da177e4SLinus Torvalds return NULL;
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds
9861da177e4SLinus Torvalds static void
get_sysnames(unsigned long type,unsigned long variation,unsigned long cpu,char ** type_name,char ** variation_name)9871da177e4SLinus Torvalds get_sysnames(unsigned long type, unsigned long variation, unsigned long cpu,
9881da177e4SLinus Torvalds char **type_name, char **variation_name)
9891da177e4SLinus Torvalds {
9901da177e4SLinus Torvalds unsigned long member;
9911da177e4SLinus Torvalds
9921da177e4SLinus Torvalds /* If not in the tables, make it UNKNOWN,
9931da177e4SLinus Torvalds else set type name to family */
99425c8716cSTobias Klauser if (type < ARRAY_SIZE(systype_names)) {
9951da177e4SLinus Torvalds *type_name = systype_names[type];
9961da177e4SLinus Torvalds } else if ((type > ST_API_BIAS) &&
99725c8716cSTobias Klauser (type - ST_API_BIAS) < ARRAY_SIZE(api_names)) {
9981da177e4SLinus Torvalds *type_name = api_names[type - ST_API_BIAS];
9991da177e4SLinus Torvalds } else if ((type > ST_UNOFFICIAL_BIAS) &&
100025c8716cSTobias Klauser (type - ST_UNOFFICIAL_BIAS) < ARRAY_SIZE(unofficial_names)) {
10011da177e4SLinus Torvalds *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS];
10021da177e4SLinus Torvalds } else {
10031da177e4SLinus Torvalds *type_name = sys_unknown;
10041da177e4SLinus Torvalds *variation_name = sys_unknown;
10051da177e4SLinus Torvalds return;
10061da177e4SLinus Torvalds }
10071da177e4SLinus Torvalds
10081da177e4SLinus Torvalds /* Set variation to "0"; if variation is zero, done. */
10091da177e4SLinus Torvalds *variation_name = systype_names[0];
10101da177e4SLinus Torvalds if (variation == 0) {
10111da177e4SLinus Torvalds return;
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds
10141da177e4SLinus Torvalds member = (variation >> 10) & 0x3f; /* member ID is a bit-field */
10151da177e4SLinus Torvalds
10161da177e4SLinus Torvalds cpu &= 0xffffffff; /* make it usable */
10171da177e4SLinus Torvalds
10181da177e4SLinus Torvalds switch (type) { /* select by family */
10191da177e4SLinus Torvalds default: /* default to variation "0" for now */
10201da177e4SLinus Torvalds break;
10211da177e4SLinus Torvalds case ST_DEC_EB164:
102203e1f044SDan Carpenter if (member >= ARRAY_SIZE(eb164_indices))
102303e1f044SDan Carpenter break;
10241da177e4SLinus Torvalds *variation_name = eb164_names[eb164_indices[member]];
10251da177e4SLinus Torvalds /* PC164 may show as EB164 variation, but with EV56 CPU,
10261da177e4SLinus Torvalds so, since no true EB164 had anything but EV5... */
10271da177e4SLinus Torvalds if (eb164_indices[member] == 0 && cpu == EV56_CPU)
10281da177e4SLinus Torvalds *variation_name = eb164_names[1]; /* make it PC164 */
10291da177e4SLinus Torvalds break;
10301da177e4SLinus Torvalds case ST_DEC_ALCOR:
103125c8716cSTobias Klauser if (member < ARRAY_SIZE(alcor_indices))
10321da177e4SLinus Torvalds *variation_name = alcor_names[alcor_indices[member]];
10331da177e4SLinus Torvalds break;
10341da177e4SLinus Torvalds case ST_DEC_EB64P:
103525c8716cSTobias Klauser if (member < ARRAY_SIZE(eb64p_indices))
10361da177e4SLinus Torvalds *variation_name = eb64p_names[eb64p_indices[member]];
10371da177e4SLinus Torvalds break;
10381da177e4SLinus Torvalds case ST_DEC_EB66:
103925c8716cSTobias Klauser if (member < ARRAY_SIZE(eb66_indices))
10401da177e4SLinus Torvalds *variation_name = eb66_names[eb66_indices[member]];
10411da177e4SLinus Torvalds break;
10421da177e4SLinus Torvalds case ST_DEC_MARVEL:
104325c8716cSTobias Klauser if (member < ARRAY_SIZE(marvel_indices))
10441da177e4SLinus Torvalds *variation_name = marvel_names[marvel_indices[member]];
10451da177e4SLinus Torvalds break;
10461da177e4SLinus Torvalds case ST_DEC_RAWHIDE:
104725c8716cSTobias Klauser if (member < ARRAY_SIZE(rawhide_indices))
10481da177e4SLinus Torvalds *variation_name = rawhide_names[rawhide_indices[member]];
10491da177e4SLinus Torvalds break;
10501da177e4SLinus Torvalds case ST_DEC_TITAN:
10511da177e4SLinus Torvalds *variation_name = titan_names[0]; /* default */
105225c8716cSTobias Klauser if (member < ARRAY_SIZE(titan_indices))
10531da177e4SLinus Torvalds *variation_name = titan_names[titan_indices[member]];
10541da177e4SLinus Torvalds break;
10551da177e4SLinus Torvalds case ST_DEC_TSUNAMI:
105625c8716cSTobias Klauser if (member < ARRAY_SIZE(tsunami_indices))
10571da177e4SLinus Torvalds *variation_name = tsunami_names[tsunami_indices[member]];
10581da177e4SLinus Torvalds break;
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds
10621da177e4SLinus Torvalds /*
10631da177e4SLinus Torvalds * A change was made to the HWRPB via an ECO and the following code
10641da177e4SLinus Torvalds * tracks a part of the ECO. In HWRPB versions less than 5, the ECO
10651da177e4SLinus Torvalds * was not implemented in the console firmware. If it's revision 5 or
10661da177e4SLinus Torvalds * greater we can get the name of the platform as an ASCII string from
10671da177e4SLinus Torvalds * the HWRPB. That's what this function does. It checks the revision
10681da177e4SLinus Torvalds * level and if the string is in the HWRPB it returns the address of
10691da177e4SLinus Torvalds * the string--a pointer to the name of the platform.
10701da177e4SLinus Torvalds *
10711da177e4SLinus Torvalds * Returns:
10721da177e4SLinus Torvalds * - Pointer to a ASCII string if it's in the HWRPB
10731da177e4SLinus Torvalds * - Pointer to a blank string if the data is not in the HWRPB.
10741da177e4SLinus Torvalds */
10751da177e4SLinus Torvalds
10761da177e4SLinus Torvalds static char *
platform_string(void)10771da177e4SLinus Torvalds platform_string(void)
10781da177e4SLinus Torvalds {
10791da177e4SLinus Torvalds struct dsr_struct *dsr;
10801da177e4SLinus Torvalds static char unk_system_string[] = "N/A";
10811da177e4SLinus Torvalds
10821da177e4SLinus Torvalds /* Go to the console for the string pointer.
10831da177e4SLinus Torvalds * If the rpb_vers is not 5 or greater the rpb
10841da177e4SLinus Torvalds * is old and does not have this data in it.
10851da177e4SLinus Torvalds */
10861da177e4SLinus Torvalds if (hwrpb->revision < 5)
10871da177e4SLinus Torvalds return (unk_system_string);
10881da177e4SLinus Torvalds else {
10891da177e4SLinus Torvalds /* The Dynamic System Recognition struct
10901da177e4SLinus Torvalds * has the system platform name starting
10911da177e4SLinus Torvalds * after the character count of the string.
10921da177e4SLinus Torvalds */
10931da177e4SLinus Torvalds dsr = ((struct dsr_struct *)
10941da177e4SLinus Torvalds ((char *)hwrpb + hwrpb->dsr_offset));
10951da177e4SLinus Torvalds return ((char *)dsr + (dsr->sysname_off +
10961da177e4SLinus Torvalds sizeof(long)));
10971da177e4SLinus Torvalds }
10981da177e4SLinus Torvalds }
10991da177e4SLinus Torvalds
11001da177e4SLinus Torvalds static int
get_nr_processors(struct percpu_struct * cpubase,unsigned long num)11011da177e4SLinus Torvalds get_nr_processors(struct percpu_struct *cpubase, unsigned long num)
11021da177e4SLinus Torvalds {
11031da177e4SLinus Torvalds struct percpu_struct *cpu;
11041da177e4SLinus Torvalds unsigned long i;
11051da177e4SLinus Torvalds int count = 0;
11061da177e4SLinus Torvalds
11071da177e4SLinus Torvalds for (i = 0; i < num; i++) {
11081da177e4SLinus Torvalds cpu = (struct percpu_struct *)
11091da177e4SLinus Torvalds ((char *)cpubase + i*hwrpb->processor_size);
11101da177e4SLinus Torvalds if ((cpu->flags & 0x1cc) == 0x1cc)
11111da177e4SLinus Torvalds count++;
11121da177e4SLinus Torvalds }
11131da177e4SLinus Torvalds return count;
11141da177e4SLinus Torvalds }
11151da177e4SLinus Torvalds
11161da177e4SLinus Torvalds static void
show_cache_size(struct seq_file * f,const char * which,int shape)11171da177e4SLinus Torvalds show_cache_size (struct seq_file *f, const char *which, int shape)
11181da177e4SLinus Torvalds {
11191da177e4SLinus Torvalds if (shape == -1)
11201da177e4SLinus Torvalds seq_printf (f, "%s\t\t: n/a\n", which);
11211da177e4SLinus Torvalds else if (shape == 0)
11221da177e4SLinus Torvalds seq_printf (f, "%s\t\t: unknown\n", which);
11231da177e4SLinus Torvalds else
11241da177e4SLinus Torvalds seq_printf (f, "%s\t\t: %dK, %d-way, %db line\n",
11251da177e4SLinus Torvalds which, shape >> 10, shape & 15,
11261da177e4SLinus Torvalds 1 << ((shape >> 4) & 15));
11271da177e4SLinus Torvalds }
11281da177e4SLinus Torvalds
11291da177e4SLinus Torvalds static int
show_cpuinfo(struct seq_file * f,void * slot)11301da177e4SLinus Torvalds show_cpuinfo(struct seq_file *f, void *slot)
11311da177e4SLinus Torvalds {
11321da177e4SLinus Torvalds extern struct unaligned_stat {
11331da177e4SLinus Torvalds unsigned long count, va, pc;
11341da177e4SLinus Torvalds } unaligned[2];
11351da177e4SLinus Torvalds
11361da177e4SLinus Torvalds static char cpu_names[][8] = {
11371da177e4SLinus Torvalds "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
11381da177e4SLinus Torvalds "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL",
11391da177e4SLinus Torvalds "EV68CX", "EV7", "EV79", "EV69"
11401da177e4SLinus Torvalds };
11411da177e4SLinus Torvalds
11421da177e4SLinus Torvalds struct percpu_struct *cpu = slot;
11431da177e4SLinus Torvalds unsigned int cpu_index;
11441da177e4SLinus Torvalds char *cpu_name;
11451da177e4SLinus Torvalds char *systype_name;
11461da177e4SLinus Torvalds char *sysvariation_name;
11471da177e4SLinus Torvalds int nr_processors;
1148fddd87d6SRichard Henderson unsigned long timer_freq;
11491da177e4SLinus Torvalds
11501da177e4SLinus Torvalds cpu_index = (unsigned) (cpu->type - 1);
11511da177e4SLinus Torvalds cpu_name = "Unknown";
115225c8716cSTobias Klauser if (cpu_index < ARRAY_SIZE(cpu_names))
11531da177e4SLinus Torvalds cpu_name = cpu_names[cpu_index];
11541da177e4SLinus Torvalds
11551da177e4SLinus Torvalds get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
11561da177e4SLinus Torvalds cpu->type, &systype_name, &sysvariation_name);
11571da177e4SLinus Torvalds
11581da177e4SLinus Torvalds nr_processors = get_nr_processors(cpu, hwrpb->nr_processors);
11591da177e4SLinus Torvalds
1160fddd87d6SRichard Henderson #if CONFIG_HZ == 1024 || CONFIG_HZ == 1200
1161fddd87d6SRichard Henderson timer_freq = (100UL * hwrpb->intr_freq) / 4096;
1162fddd87d6SRichard Henderson #else
1163fddd87d6SRichard Henderson timer_freq = 100UL * CONFIG_HZ;
1164fddd87d6SRichard Henderson #endif
1165fddd87d6SRichard Henderson
11661da177e4SLinus Torvalds seq_printf(f, "cpu\t\t\t: Alpha\n"
11671da177e4SLinus Torvalds "cpu model\t\t: %s\n"
11681da177e4SLinus Torvalds "cpu variation\t\t: %ld\n"
11691da177e4SLinus Torvalds "cpu revision\t\t: %ld\n"
11701da177e4SLinus Torvalds "cpu serial number\t: %s\n"
11711da177e4SLinus Torvalds "system type\t\t: %s\n"
11721da177e4SLinus Torvalds "system variation\t: %s\n"
11731da177e4SLinus Torvalds "system revision\t\t: %ld\n"
11741da177e4SLinus Torvalds "system serial number\t: %s\n"
11751da177e4SLinus Torvalds "cycle frequency [Hz]\t: %lu %s\n"
11761da177e4SLinus Torvalds "timer frequency [Hz]\t: %lu.%02lu\n"
11771da177e4SLinus Torvalds "page size [bytes]\t: %ld\n"
11781da177e4SLinus Torvalds "phys. address bits\t: %ld\n"
11791da177e4SLinus Torvalds "max. addr. space #\t: %ld\n"
11801da177e4SLinus Torvalds "BogoMIPS\t\t: %lu.%02lu\n"
11811da177e4SLinus Torvalds "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
11821da177e4SLinus Torvalds "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
11831da177e4SLinus Torvalds "platform string\t\t: %s\n"
11841da177e4SLinus Torvalds "cpus detected\t\t: %d\n",
11851da177e4SLinus Torvalds cpu_name, cpu->variation, cpu->revision,
11861da177e4SLinus Torvalds (char*)cpu->serial_no,
11871da177e4SLinus Torvalds systype_name, sysvariation_name, hwrpb->sys_revision,
11881da177e4SLinus Torvalds (char*)hwrpb->ssn,
11891da177e4SLinus Torvalds est_cycle_freq ? : hwrpb->cycle_freq,
11901da177e4SLinus Torvalds est_cycle_freq ? "est." : "",
1191fddd87d6SRichard Henderson timer_freq / 100, timer_freq % 100,
11921da177e4SLinus Torvalds hwrpb->pagesize,
11931da177e4SLinus Torvalds hwrpb->pa_bits,
11941da177e4SLinus Torvalds hwrpb->max_asn,
11951da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ),
11961da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100,
11971da177e4SLinus Torvalds unaligned[0].count, unaligned[0].pc, unaligned[0].va,
11981da177e4SLinus Torvalds unaligned[1].count, unaligned[1].pc, unaligned[1].va,
11991da177e4SLinus Torvalds platform_string(), nr_processors);
12001da177e4SLinus Torvalds
12011da177e4SLinus Torvalds #ifdef CONFIG_SMP
12025f0e3da6SRandy Dunlap seq_printf(f, "cpus active\t\t: %u\n"
12031da177e4SLinus Torvalds "cpu active mask\t\t: %016lx\n",
120481740fc6SKOSAKI Motohiro num_online_cpus(), cpumask_bits(cpu_possible_mask)[0]);
12051da177e4SLinus Torvalds #endif
12061da177e4SLinus Torvalds
12071da177e4SLinus Torvalds show_cache_size (f, "L1 Icache", alpha_l1i_cacheshape);
12081da177e4SLinus Torvalds show_cache_size (f, "L1 Dcache", alpha_l1d_cacheshape);
12091da177e4SLinus Torvalds show_cache_size (f, "L2 cache", alpha_l2_cacheshape);
12101da177e4SLinus Torvalds show_cache_size (f, "L3 cache", alpha_l3_cacheshape);
12111da177e4SLinus Torvalds
12121da177e4SLinus Torvalds return 0;
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds
12151da177e4SLinus Torvalds static int __init
read_mem_block(int * addr,int stride,int size)12161da177e4SLinus Torvalds read_mem_block(int *addr, int stride, int size)
12171da177e4SLinus Torvalds {
12181da177e4SLinus Torvalds long nloads = size / stride, cnt, tmp;
12191da177e4SLinus Torvalds
12201da177e4SLinus Torvalds __asm__ __volatile__(
12211da177e4SLinus Torvalds " rpcc %0\n"
12221da177e4SLinus Torvalds "1: ldl %3,0(%2)\n"
12231da177e4SLinus Torvalds " subq %1,1,%1\n"
12241da177e4SLinus Torvalds /* Next two XORs introduce an explicit data dependency between
12251da177e4SLinus Torvalds consecutive loads in the loop, which will give us true load
12261da177e4SLinus Torvalds latency. */
12271da177e4SLinus Torvalds " xor %3,%2,%2\n"
12281da177e4SLinus Torvalds " xor %3,%2,%2\n"
12291da177e4SLinus Torvalds " addq %2,%4,%2\n"
12301da177e4SLinus Torvalds " bne %1,1b\n"
12311da177e4SLinus Torvalds " rpcc %3\n"
12321da177e4SLinus Torvalds " subl %3,%0,%0\n"
12331da177e4SLinus Torvalds : "=&r" (cnt), "=&r" (nloads), "=&r" (addr), "=&r" (tmp)
12341da177e4SLinus Torvalds : "r" (stride), "1" (nloads), "2" (addr));
12351da177e4SLinus Torvalds
12361da177e4SLinus Torvalds return cnt / (size / stride);
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds
12391da177e4SLinus Torvalds #define CSHAPE(totalsize, linesize, assoc) \
12401da177e4SLinus Torvalds ((totalsize & ~0xff) | (linesize << 4) | assoc)
12411da177e4SLinus Torvalds
12421da177e4SLinus Torvalds /* ??? EV5 supports up to 64M, but did the systems with more than
12431da177e4SLinus Torvalds 16M of BCACHE ever exist? */
12441da177e4SLinus Torvalds #define MAX_BCACHE_SIZE 16*1024*1024
12451da177e4SLinus Torvalds
12461da177e4SLinus Torvalds /* Note that the offchip caches are direct mapped on all Alphas. */
12471da177e4SLinus Torvalds static int __init
external_cache_probe(int minsize,int width)12481da177e4SLinus Torvalds external_cache_probe(int minsize, int width)
12491da177e4SLinus Torvalds {
12501da177e4SLinus Torvalds int cycles, prev_cycles = 1000000;
12511da177e4SLinus Torvalds int stride = 1 << width;
12521da177e4SLinus Torvalds long size = minsize, maxsize = MAX_BCACHE_SIZE * 2;
12531da177e4SLinus Torvalds
12541da177e4SLinus Torvalds if (maxsize > (max_low_pfn + 1) << PAGE_SHIFT)
125574fd1b68SRichard Henderson maxsize = 1 << (ilog2(max_low_pfn + 1) + PAGE_SHIFT);
12561da177e4SLinus Torvalds
12571da177e4SLinus Torvalds /* Get the first block cached. */
12581da177e4SLinus Torvalds read_mem_block(__va(0), stride, size);
12591da177e4SLinus Torvalds
12601da177e4SLinus Torvalds while (size < maxsize) {
12611da177e4SLinus Torvalds /* Get an average load latency in cycles. */
12621da177e4SLinus Torvalds cycles = read_mem_block(__va(0), stride, size);
12631da177e4SLinus Torvalds if (cycles > prev_cycles * 2) {
12641da177e4SLinus Torvalds /* Fine, we exceed the cache. */
12651da177e4SLinus Torvalds printk("%ldK Bcache detected; load hit latency %d "
12661da177e4SLinus Torvalds "cycles, load miss latency %d cycles\n",
12671da177e4SLinus Torvalds size >> 11, prev_cycles, cycles);
12681da177e4SLinus Torvalds return CSHAPE(size >> 1, width, 1);
12691da177e4SLinus Torvalds }
12701da177e4SLinus Torvalds /* Try to get the next block cached. */
12711da177e4SLinus Torvalds read_mem_block(__va(size), stride, size);
12721da177e4SLinus Torvalds prev_cycles = cycles;
12731da177e4SLinus Torvalds size <<= 1;
12741da177e4SLinus Torvalds }
12751da177e4SLinus Torvalds return -1; /* No BCACHE found. */
12761da177e4SLinus Torvalds }
12771da177e4SLinus Torvalds
12781da177e4SLinus Torvalds static void __init
determine_cpu_caches(unsigned int cpu_type)12791da177e4SLinus Torvalds determine_cpu_caches (unsigned int cpu_type)
12801da177e4SLinus Torvalds {
12811da177e4SLinus Torvalds int L1I, L1D, L2, L3;
12821da177e4SLinus Torvalds
12831da177e4SLinus Torvalds switch (cpu_type) {
12841da177e4SLinus Torvalds case EV4_CPU:
12851da177e4SLinus Torvalds case EV45_CPU:
12861da177e4SLinus Torvalds {
12871da177e4SLinus Torvalds if (cpu_type == EV4_CPU)
12881da177e4SLinus Torvalds L1I = CSHAPE(8*1024, 5, 1);
12891da177e4SLinus Torvalds else
12901da177e4SLinus Torvalds L1I = CSHAPE(16*1024, 5, 1);
12911da177e4SLinus Torvalds L1D = L1I;
12921da177e4SLinus Torvalds L3 = -1;
12931da177e4SLinus Torvalds
12941da177e4SLinus Torvalds /* BIU_CTL is a write-only Abox register. PALcode has a
12951da177e4SLinus Torvalds shadow copy, and may be available from some versions
12961da177e4SLinus Torvalds of the CSERVE PALcall. If we can get it, then
12971da177e4SLinus Torvalds
12981da177e4SLinus Torvalds unsigned long biu_ctl, size;
12991da177e4SLinus Torvalds size = 128*1024 * (1 << ((biu_ctl >> 28) & 7));
13001da177e4SLinus Torvalds L2 = CSHAPE (size, 5, 1);
13011da177e4SLinus Torvalds
13021da177e4SLinus Torvalds Unfortunately, we can't rely on that.
13031da177e4SLinus Torvalds */
13041da177e4SLinus Torvalds L2 = external_cache_probe(128*1024, 5);
13051da177e4SLinus Torvalds break;
13061da177e4SLinus Torvalds }
13071da177e4SLinus Torvalds
13081da177e4SLinus Torvalds case LCA4_CPU:
13091da177e4SLinus Torvalds {
13101da177e4SLinus Torvalds unsigned long car, size;
13111da177e4SLinus Torvalds
13121da177e4SLinus Torvalds L1I = L1D = CSHAPE(8*1024, 5, 1);
13131da177e4SLinus Torvalds L3 = -1;
13141da177e4SLinus Torvalds
13151da177e4SLinus Torvalds car = *(vuip) phys_to_virt (0x120000078UL);
13161da177e4SLinus Torvalds size = 64*1024 * (1 << ((car >> 5) & 7));
13171da177e4SLinus Torvalds /* No typo -- 8 byte cacheline size. Whodathunk. */
13181da177e4SLinus Torvalds L2 = (car & 1 ? CSHAPE (size, 3, 1) : -1);
13191da177e4SLinus Torvalds break;
13201da177e4SLinus Torvalds }
13211da177e4SLinus Torvalds
13221da177e4SLinus Torvalds case EV5_CPU:
13231da177e4SLinus Torvalds case EV56_CPU:
13241da177e4SLinus Torvalds {
13251da177e4SLinus Torvalds unsigned long sc_ctl, width;
13261da177e4SLinus Torvalds
13271da177e4SLinus Torvalds L1I = L1D = CSHAPE(8*1024, 5, 1);
13281da177e4SLinus Torvalds
13291da177e4SLinus Torvalds /* Check the line size of the Scache. */
13301da177e4SLinus Torvalds sc_ctl = *(vulp) phys_to_virt (0xfffff000a8UL);
13311da177e4SLinus Torvalds width = sc_ctl & 0x1000 ? 6 : 5;
13321da177e4SLinus Torvalds L2 = CSHAPE (96*1024, width, 3);
13331da177e4SLinus Torvalds
13341da177e4SLinus Torvalds /* BC_CONTROL and BC_CONFIG are write-only IPRs. PALcode
13351da177e4SLinus Torvalds has a shadow copy, and may be available from some versions
13361da177e4SLinus Torvalds of the CSERVE PALcall. If we can get it, then
13371da177e4SLinus Torvalds
13381da177e4SLinus Torvalds unsigned long bc_control, bc_config, size;
13391da177e4SLinus Torvalds size = 1024*1024 * (1 << ((bc_config & 7) - 1));
13401da177e4SLinus Torvalds L3 = (bc_control & 1 ? CSHAPE (size, width, 1) : -1);
13411da177e4SLinus Torvalds
13421da177e4SLinus Torvalds Unfortunately, we can't rely on that.
13431da177e4SLinus Torvalds */
13441da177e4SLinus Torvalds L3 = external_cache_probe(1024*1024, width);
13451da177e4SLinus Torvalds break;
13461da177e4SLinus Torvalds }
13471da177e4SLinus Torvalds
13481da177e4SLinus Torvalds case PCA56_CPU:
13491da177e4SLinus Torvalds case PCA57_CPU:
13501da177e4SLinus Torvalds {
13511da177e4SLinus Torvalds if (cpu_type == PCA56_CPU) {
13521da177e4SLinus Torvalds L1I = CSHAPE(16*1024, 6, 1);
13531da177e4SLinus Torvalds L1D = CSHAPE(8*1024, 5, 1);
13541da177e4SLinus Torvalds } else {
13551da177e4SLinus Torvalds L1I = CSHAPE(32*1024, 6, 2);
13561da177e4SLinus Torvalds L1D = CSHAPE(16*1024, 5, 1);
13571da177e4SLinus Torvalds }
13581da177e4SLinus Torvalds L3 = -1;
13591da177e4SLinus Torvalds
1360280da4e4SRichard Henderson #if 0
1361280da4e4SRichard Henderson unsigned long cbox_config, size;
1362280da4e4SRichard Henderson
13631da177e4SLinus Torvalds cbox_config = *(vulp) phys_to_virt (0xfffff00008UL);
13641da177e4SLinus Torvalds size = 512*1024 * (1 << ((cbox_config >> 12) & 3));
13651da177e4SLinus Torvalds
13661da177e4SLinus Torvalds L2 = ((cbox_config >> 31) & 1 ? CSHAPE (size, 6, 1) : -1);
13671da177e4SLinus Torvalds #else
13681da177e4SLinus Torvalds L2 = external_cache_probe(512*1024, 6);
13691da177e4SLinus Torvalds #endif
13701da177e4SLinus Torvalds break;
13711da177e4SLinus Torvalds }
13721da177e4SLinus Torvalds
13731da177e4SLinus Torvalds case EV6_CPU:
13741da177e4SLinus Torvalds case EV67_CPU:
13751da177e4SLinus Torvalds case EV68CB_CPU:
13761da177e4SLinus Torvalds case EV68AL_CPU:
13771da177e4SLinus Torvalds case EV68CX_CPU:
13781da177e4SLinus Torvalds case EV69_CPU:
13791da177e4SLinus Torvalds L1I = L1D = CSHAPE(64*1024, 6, 2);
13801da177e4SLinus Torvalds L2 = external_cache_probe(1024*1024, 6);
13811da177e4SLinus Torvalds L3 = -1;
13821da177e4SLinus Torvalds break;
13831da177e4SLinus Torvalds
13841da177e4SLinus Torvalds case EV7_CPU:
13851da177e4SLinus Torvalds case EV79_CPU:
13861da177e4SLinus Torvalds L1I = L1D = CSHAPE(64*1024, 6, 2);
13871da177e4SLinus Torvalds L2 = CSHAPE(7*1024*1024/4, 6, 7);
13881da177e4SLinus Torvalds L3 = -1;
13891da177e4SLinus Torvalds break;
13901da177e4SLinus Torvalds
13911da177e4SLinus Torvalds default:
13921da177e4SLinus Torvalds /* Nothing known about this cpu type. */
13931da177e4SLinus Torvalds L1I = L1D = L2 = L3 = 0;
13941da177e4SLinus Torvalds break;
13951da177e4SLinus Torvalds }
13961da177e4SLinus Torvalds
13971da177e4SLinus Torvalds alpha_l1i_cacheshape = L1I;
13981da177e4SLinus Torvalds alpha_l1d_cacheshape = L1D;
13991da177e4SLinus Torvalds alpha_l2_cacheshape = L2;
14001da177e4SLinus Torvalds alpha_l3_cacheshape = L3;
14011da177e4SLinus Torvalds }
14021da177e4SLinus Torvalds
14031da177e4SLinus Torvalds /*
14041da177e4SLinus Torvalds * We show only CPU #0 info.
14051da177e4SLinus Torvalds */
14061da177e4SLinus Torvalds static void *
c_start(struct seq_file * f,loff_t * pos)14071da177e4SLinus Torvalds c_start(struct seq_file *f, loff_t *pos)
14081da177e4SLinus Torvalds {
14091da177e4SLinus Torvalds return *pos ? NULL : (char *)hwrpb + hwrpb->processor_offset;
14101da177e4SLinus Torvalds }
14111da177e4SLinus Torvalds
14121da177e4SLinus Torvalds static void *
c_next(struct seq_file * f,void * v,loff_t * pos)14131da177e4SLinus Torvalds c_next(struct seq_file *f, void *v, loff_t *pos)
14141da177e4SLinus Torvalds {
14157812193cSMatt Turner (*pos)++;
14161da177e4SLinus Torvalds return NULL;
14171da177e4SLinus Torvalds }
14181da177e4SLinus Torvalds
14191da177e4SLinus Torvalds static void
c_stop(struct seq_file * f,void * v)14201da177e4SLinus Torvalds c_stop(struct seq_file *f, void *v)
14211da177e4SLinus Torvalds {
14221da177e4SLinus Torvalds }
14231da177e4SLinus Torvalds
142403a44825SJan Engelhardt const struct seq_operations cpuinfo_op = {
14251da177e4SLinus Torvalds .start = c_start,
14261da177e4SLinus Torvalds .next = c_next,
14271da177e4SLinus Torvalds .stop = c_stop,
14281da177e4SLinus Torvalds .show = show_cpuinfo,
14291da177e4SLinus Torvalds };
14301da177e4SLinus Torvalds
14311da177e4SLinus Torvalds
14321da177e4SLinus Torvalds static int
alpha_panic_event(struct notifier_block * this,unsigned long event,void * ptr)14331da177e4SLinus Torvalds alpha_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
14341da177e4SLinus Torvalds {
14351da177e4SLinus Torvalds #if 1
14361da177e4SLinus Torvalds /* FIXME FIXME FIXME */
14371da177e4SLinus Torvalds /* If we are using SRM and serial console, just hard halt here. */
14381da177e4SLinus Torvalds if (alpha_using_srm && srmcons_output)
14391da177e4SLinus Torvalds __halt();
14401da177e4SLinus Torvalds #endif
14411da177e4SLinus Torvalds return NOTIFY_DONE;
14421da177e4SLinus Torvalds }
1443e5c6c8e4SMichael Neuling
add_pcspkr(void)1444e5c6c8e4SMichael Neuling static __init int add_pcspkr(void)
1445e5c6c8e4SMichael Neuling {
1446e5c6c8e4SMichael Neuling struct platform_device *pd;
1447e5c6c8e4SMichael Neuling int ret;
1448e5c6c8e4SMichael Neuling
1449e5c6c8e4SMichael Neuling pd = platform_device_alloc("pcspkr", -1);
1450e5c6c8e4SMichael Neuling if (!pd)
1451e5c6c8e4SMichael Neuling return -ENOMEM;
1452e5c6c8e4SMichael Neuling
1453e5c6c8e4SMichael Neuling ret = platform_device_add(pd);
1454e5c6c8e4SMichael Neuling if (ret)
1455e5c6c8e4SMichael Neuling platform_device_put(pd);
1456e5c6c8e4SMichael Neuling
1457e5c6c8e4SMichael Neuling return ret;
1458e5c6c8e4SMichael Neuling }
1459e5c6c8e4SMichael Neuling device_initcall(add_pcspkr);
1460