[S390] codepage conversion of kernel parameter line
[safe/jmp/linux-2.6] / arch / ia64 / kernel / setup.c
index 088e5dd..a1ea879 100644 (file)
@@ -22,7 +22,6 @@
  * 06/24/99 W.Drummond added boot_cpu_data.
  * 05/28/05 Z. Menyhart        Dynamic stride size for "flush_icache_range()"
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
 #include <linux/seq_file.h>
 #include <linux/string.h>
 #include <linux/threads.h>
-#include <linux/tty.h>
+#include <linux/screen_info.h>
+#include <linux/dmi.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/efi.h>
 #include <linux/initrd.h>
-#include <linux/platform.h>
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
 
 #include <asm/ia32.h>
 #include <asm/machvec.h>
 #include <asm/mca.h>
 #include <asm/meminit.h>
 #include <asm/page.h>
+#include <asm/paravirt.h>
+#include <asm/paravirt_patch.h>
 #include <asm/patch.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
 #include <asm/sections.h>
-#include <asm/serial.h>
 #include <asm/setup.h>
 #include <asm/smp.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
 #include <asm/unistd.h>
+#include <asm/hpsim.h>
 
 #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
 # error "struct cpuinfo_ia64 too big!"
@@ -70,9 +74,8 @@ unsigned long __per_cpu_offset[NR_CPUS];
 EXPORT_SYMBOL(__per_cpu_offset);
 #endif
 
-DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
+DEFINE_PER_CPU(struct cpuinfo_ia64, ia64_cpu_info);
 DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
-DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8);
 unsigned long ia64_cycles_per_usec;
 struct ia64_boot_param *ia64_boot_param;
 struct screen_info screen_info;
@@ -88,9 +91,11 @@ static struct resource code_resource = {
        .name   = "Kernel code",
        .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
 };
-extern void efi_initialize_iomem_resources(struct resource *,
-               struct resource *);
-extern char _text[], _end[], _etext[];
+
+static struct resource bss_resource = {
+       .name   = "Kernel bss",
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
 
 unsigned long ia64_max_cacheline_size;
 
@@ -112,6 +117,13 @@ unsigned int num_io_spaces;
  */
 #define        I_CACHE_STRIDE_SHIFT    5       /* Safest way to go: 32 bytes by 32 bytes */
 unsigned long ia64_i_cache_stride_shift = ~0;
+/*
+ * "clflush_cache_range()" needs to know what processor dependent stride size to
+ * use when it flushes cache lines including both d-cache and i-cache.
+ */
+/* Safest way to go: 32 bytes by 32 bytes */
+#define        CACHE_STRIDE_SHIFT      5
+unsigned long ia64_cache_stride_shift = ~0;
 
 /*
  * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1).  This
@@ -128,8 +140,8 @@ EXPORT_SYMBOL(ia64_max_iommu_merge_mask);
 /*
  * We use a special marker for the end of memory and it uses the extra (+1) slot
  */
-struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1];
-int num_rsvd_regions;
+struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1] __initdata;
+int num_rsvd_regions __initdata;
 
 
 /*
@@ -138,10 +150,10 @@ int num_rsvd_regions;
  * caller-specified function is called with the memory ranges that remain after filtering.
  * This routine does not assume the incoming segments are sorted.
  */
-int
-filter_rsvd_memory (unsigned long start, unsigned long end, void *arg)
+int __init
+filter_rsvd_memory (u64 start, u64 end, void *arg)
 {
-       unsigned long range_start, range_end, prev_start;
+       u64 range_start, range_end, prev_start;
        void (*func)(unsigned long, unsigned long, int);
        int i;
 
@@ -174,7 +186,30 @@ filter_rsvd_memory (unsigned long start, unsigned long end, void *arg)
        return 0;
 }
 
-static void
+/*
+ * Similar to "filter_rsvd_memory()", but the reserved memory ranges
+ * are not filtered out.
+ */
+int __init
+filter_memory(u64 start, u64 end, void *arg)
+{
+       void (*func)(unsigned long, unsigned long, int);
+
+#if IGNORE_PFN0
+       if (start == PAGE_OFFSET) {
+               printk(KERN_WARNING "warning: skipping physical page 0\n");
+               start += PAGE_SIZE;
+               if (start >= end)
+                       return 0;
+       }
+#endif
+       func = arg;
+       if (start < end)
+               call_pernode_memory(__pa(start), end - start, func);
+       return 0;
+}
+
+static void __init
 sort_regions (struct rsvd_region *rsvd_region, int max)
 {
        int j;
@@ -200,25 +235,100 @@ static int __init register_memory(void)
        code_resource.start = ia64_tpa(_text);
        code_resource.end   = ia64_tpa(_etext) - 1;
        data_resource.start = ia64_tpa(_etext);
-       data_resource.end   = ia64_tpa(_end) - 1;
-       efi_initialize_iomem_resources(&code_resource, &data_resource);
+       data_resource.end   = ia64_tpa(_edata) - 1;
+       bss_resource.start  = ia64_tpa(__bss_start);
+       bss_resource.end    = ia64_tpa(_end) - 1;
+       efi_initialize_iomem_resources(&code_resource, &data_resource,
+                       &bss_resource);
 
        return 0;
 }
 
 __initcall(register_memory);
 
+
+#ifdef CONFIG_KEXEC
+
+/*
+ * This function checks if the reserved crashkernel is allowed on the specific
+ * IA64 machine flavour. Machines without an IO TLB use swiotlb and require
+ * some memory below 4 GB (i.e. in 32 bit area), see the implementation of
+ * lib/swiotlb.c. The hpzx1 architecture has an IO TLB but cannot use that
+ * in kdump case. See the comment in sba_init() in sba_iommu.c.
+ *
+ * So, the only machvec that really supports loading the kdump kernel
+ * over 4 GB is "sn2".
+ */
+static int __init check_crashkernel_memory(unsigned long pbase, size_t size)
+{
+       if (ia64_platform_is("sn2") || ia64_platform_is("uv"))
+               return 1;
+       else
+               return pbase < (1UL << 32);
+}
+
+static void __init setup_crashkernel(unsigned long total, int *n)
+{
+       unsigned long long base = 0, size = 0;
+       int ret;
+
+       ret = parse_crashkernel(boot_command_line, total,
+                       &size, &base);
+       if (ret == 0 && size > 0) {
+               if (!base) {
+                       sort_regions(rsvd_region, *n);
+                       base = kdump_find_rsvd_region(size,
+                                       rsvd_region, *n);
+               }
+
+               if (!check_crashkernel_memory(base, size)) {
+                       pr_warning("crashkernel: There would be kdump memory "
+                               "at %ld GB but this is unusable because it "
+                               "must\nbe below 4 GB. Change the memory "
+                               "configuration of the machine.\n",
+                               (unsigned long)(base >> 30));
+                       return;
+               }
+
+               if (base != ~0UL) {
+                       printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+                                       "for crashkernel (System RAM: %ldMB)\n",
+                                       (unsigned long)(size >> 20),
+                                       (unsigned long)(base >> 20),
+                                       (unsigned long)(total >> 20));
+                       rsvd_region[*n].start =
+                               (unsigned long)__va(base);
+                       rsvd_region[*n].end =
+                               (unsigned long)__va(base + size);
+                       (*n)++;
+                       crashk_res.start = base;
+                       crashk_res.end = base + size - 1;
+               }
+       }
+       efi_memmap_res.start = ia64_boot_param->efi_memmap;
+       efi_memmap_res.end = efi_memmap_res.start +
+               ia64_boot_param->efi_memmap_size;
+       boot_param_res.start = __pa(ia64_boot_param);
+       boot_param_res.end = boot_param_res.start +
+               sizeof(*ia64_boot_param);
+}
+#else
+static inline void __init setup_crashkernel(unsigned long total, int *n)
+{}
+#endif
+
 /**
  * reserve_memory - setup reserved memory areas
  *
  * Setup the reserved memory areas set aside for the boot parameters,
  * initrd, etc.  There are currently %IA64_MAX_RSVD_REGIONS defined,
- * see include/asm-ia64/meminit.h if you need to define more.
+ * see arch/ia64/include/asm/meminit.h if you need to define more.
  */
-void
+void __init
 reserve_memory (void)
 {
        int n = 0;
+       unsigned long total_memory;
 
        /*
         * none of the entries in this table overlap
@@ -240,6 +350,8 @@ reserve_memory (void)
        rsvd_region[n].end   = (unsigned long) ia64_imva(_end);
        n++;
 
+       n += paravirt_reserve_memory(&rsvd_region[n]);
+
 #ifdef CONFIG_BLK_DEV_INITRD
        if (ia64_boot_param->initrd_start) {
                rsvd_region[n].start = (unsigned long)__va(ia64_boot_param->initrd_start);
@@ -248,26 +360,36 @@ reserve_memory (void)
        }
 #endif
 
-       efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
+#ifdef CONFIG_CRASH_DUMP
+       if (reserve_elfcorehdr(&rsvd_region[n].start,
+                              &rsvd_region[n].end) == 0)
+               n++;
+#endif
+
+       total_memory = efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
        n++;
 
+       setup_crashkernel(total_memory, &n);
+
        /* end of memory marker */
        rsvd_region[n].start = ~0UL;
        rsvd_region[n].end   = ~0UL;
        n++;
 
        num_rsvd_regions = n;
+       BUG_ON(IA64_MAX_RSVD_REGIONS + 1 < n);
 
        sort_regions(rsvd_region, num_rsvd_regions);
 }
 
+
 /**
  * find_initrd - get initrd parameters from the boot parameter structure
  *
  * Grab the initrd start and end from the boot parameter struct given us by
  * the boot loader.
  */
-void
+void __init
 find_initrd (void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -275,7 +397,7 @@ find_initrd (void)
                initrd_start = (unsigned long)__va(ia64_boot_param->initrd_start);
                initrd_end   = initrd_start+ia64_boot_param->initrd_size;
 
-               printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n",
+               printk(KERN_INFO "Initial ramdisk at: 0x%lx (%llu bytes)\n",
                       initrd_start, ia64_boot_param->initrd_size);
        }
 #endif
@@ -341,10 +463,8 @@ early_console_setup (char *cmdline)
        if (!efi_setup_pcdp_console(cmdline))
                earlycons++;
 #endif
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-       if (!early_serial_console_init(cmdline))
+       if (!simcons_register())
                earlycons++;
-#endif
 
        return (earlycons) ? 0 : -1;
 }
@@ -358,107 +478,124 @@ mark_bsp_online (void)
 #endif
 }
 
-#ifdef CONFIG_SMP
-static void
-check_for_logical_procs (void)
+static __initdata int nomca;
+static __init int setup_nomca(char *s)
 {
-       pal_logical_to_physical_t info;
-       s64 status;
-
-       status = ia64_pal_logical_to_phys(0, &info);
-       if (status == -1) {
-               printk(KERN_INFO "No logical to physical processor mapping "
-                      "available\n");
-               return;
-       }
-       if (status) {
-               printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
-                      status);
-               return;
-       }
-       /*
-        * Total number of siblings that BSP has.  Though not all of them 
-        * may have booted successfully. The correct number of siblings 
-        * booted is in info.overview_num_log.
+       nomca = 1;
+       return 0;
+}
+early_param("nomca", setup_nomca);
+
+/*
+ * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
+ * is_kdump_kernel() to determine if we are booting after a panic. Hence
+ * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
+ */
+#ifdef CONFIG_CRASH_DUMP
+/* elfcorehdr= specifies the location of elf core header
+ * stored by the crashed kernel.
+ */
+static int __init parse_elfcorehdr(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+
+        elfcorehdr_addr = memparse(arg, &arg);
+       return 0;
+}
+early_param("elfcorehdr", parse_elfcorehdr);
+
+int __init reserve_elfcorehdr(u64 *start, u64 *end)
+{
+       u64 length;
+
+       /* We get the address using the kernel command line,
+        * but the size is extracted from the EFI tables.
+        * Both address and size are required for reservation
+        * to work properly.
         */
-       smp_num_siblings = info.overview_tpc;
-       smp_num_cpucores = info.overview_cpp;
+
+       if (!is_vmcore_usable())
+               return -EINVAL;
+
+       if ((length = vmcore_find_descriptor_size(elfcorehdr_addr)) == 0) {
+               vmcore_unusable();
+               return -EINVAL;
+       }
+
+       *start = (unsigned long)__va(elfcorehdr_addr);
+       *end = *start + length;
+       return 0;
 }
-#endif
+
+#endif /* CONFIG_PROC_VMCORE */
 
 void __init
 setup_arch (char **cmdline_p)
 {
        unw_init();
 
+       paravirt_arch_setup_early();
+
        ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
+       paravirt_patch_apply();
 
        *cmdline_p = __va(ia64_boot_param->command_line);
-       strlcpy(saved_command_line, *cmdline_p, COMMAND_LINE_SIZE);
+       strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
 
        efi_init();
        io_port_init();
 
 #ifdef CONFIG_IA64_GENERIC
-       {
-               const char *mvec_name = strstr (*cmdline_p, "machvec=");
-               char str[64];
-
-               if (mvec_name) {
-                       const char *end;
-                       size_t len;
-
-                       mvec_name += 8;
-                       end = strchr (mvec_name, ' ');
-                       if (end)
-                               len = end - mvec_name;
-                       else
-                               len = strlen (mvec_name);
-                       len = min(len, sizeof (str) - 1);
-                       strncpy (str, mvec_name, len);
-                       str[len] = '\0';
-                       mvec_name = str;
-               } else
-                       mvec_name = acpi_get_sysname();
-               machvec_init(mvec_name);
-       }
+       /* machvec needs to be parsed from the command line
+        * before parse_early_param() is called to ensure
+        * that ia64_mv is initialised before any command line
+        * settings may cause console setup to occur
+        */
+       machvec_init_from_cmdline(*cmdline_p);
 #endif
 
+       parse_early_param();
+
        if (early_console_setup(*cmdline_p) == 0)
                mark_bsp_online();
 
 #ifdef CONFIG_ACPI
        /* Initialize the ACPI boot-time table parser */
        acpi_table_init();
+       early_acpi_boot_init();
 # ifdef CONFIG_ACPI_NUMA
        acpi_numa_init();
-# endif
-#else
-# ifdef CONFIG_SMP
-       smp_build_cpu_map();    /* happens, e.g., with the Ski simulator */
+#  ifdef CONFIG_ACPI_HOTPLUG_CPU
+       prefill_possible_map();
+#  endif
+       per_cpu_scan_finalize((cpus_weight(early_cpu_possible_map) == 0 ?
+               32 : cpus_weight(early_cpu_possible_map)),
+               additional_cpus > 0 ? additional_cpus : 0);
 # endif
 #endif /* CONFIG_APCI_BOOT */
 
+#ifdef CONFIG_SMP
+       smp_build_cpu_map();
+#endif
        find_memory();
 
        /* process SAL system table: */
-       ia64_sal_init(efi.sal_systab);
+       ia64_sal_init(__va(efi.sal_systab));
+
+#ifdef CONFIG_ITANIUM
+       ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist);
+#else
+       {
+               unsigned long num_phys_stacked;
+
+               if (ia64_pal_rse_info(&num_phys_stacked, 0) == 0 && num_phys_stacked > 96)
+                       ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist);
+       }
+#endif
 
 #ifdef CONFIG_SMP
        cpu_physical_id(0) = hard_smp_processor_id();
-
-       cpu_set(0, cpu_sibling_map[0]);
-       cpu_set(0, cpu_core_map[0]);
-
-       check_for_logical_procs();
-       if (smp_num_cpucores > 1)
-               printk(KERN_INFO
-                      "cpu package is Multi-Core capable: number of cores=%d\n",
-                      smp_num_cpucores);
-       if (smp_num_siblings > 1)
-               printk(KERN_INFO
-                      "cpu package is Multi-Threading capable: number of siblings=%d\n",
-                      smp_num_siblings);
 #endif
 
        cpu_init();     /* initialize the bootstrap CPU */
@@ -468,6 +605,9 @@ setup_arch (char **cmdline_p)
        acpi_boot_init();
 #endif
 
+       paravirt_banner();
+       paravirt_arch_setup_console(cmdline_p);
+
 #ifdef CONFIG_VT
        if (!conswitchp) {
 # if defined(CONFIG_DUMMY_CONSOLE)
@@ -487,15 +627,20 @@ setup_arch (char **cmdline_p)
 #endif
 
        /* enable IA-64 Machine Check Abort Handling unless disabled */
-       if (!strstr(saved_command_line, "nomca"))
+       if (paravirt_arch_setup_nomca())
+               nomca = 1;
+       if (!nomca)
                ia64_mca_init();
 
        platform_setup(cmdline_p);
+#ifndef CONFIG_IA64_HP_SIM
+       check_sal_cache_flush();
+#endif
        paging_init();
 }
 
 /*
- * Display cpu info for all cpu's.
+ * Display cpu info for all CPUs.
  */
 static int
 show_cpuinfo (struct seq_file *m, void *v)
@@ -515,40 +660,31 @@ show_cpuinfo (struct seq_file *m, void *v)
                { 1UL << 1, "spontaneous deferral"},
                { 1UL << 2, "16-byte atomic ops" }
        };
-       char family[32], features[128], *cp, sep;
+       char features[128], *cp, *sep;
        struct cpuinfo_ia64 *c = v;
        unsigned long mask;
-       unsigned int proc_freq;
-       int i;
+       unsigned long proc_freq;
+       int i, size;
 
        mask = c->features;
 
-       switch (c->family) {
-             case 0x07:        memcpy(family, "Itanium", 8); break;
-             case 0x1f:        memcpy(family, "Itanium 2", 10); break;
-             default:          sprintf(family, "%u", c->family); break;
-       }
-
        /* build the feature string: */
-       memcpy(features, " standard", 10);
+       memcpy(features, "standard", 9);
        cp = features;
-       sep = 0;
-       for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) {
+       size = sizeof(features);
+       sep = "";
+       for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) {
                if (mask & feature_bits[i].mask) {
-                       if (sep)
-                               *cp++ = sep;
-                       sep = ',';
-                       *cp++ = ' ';
-                       strcpy(cp, feature_bits[i].feature_name);
-                       cp += strlen(feature_bits[i].feature_name);
+                       cp += snprintf(cp, size, "%s%s", sep,
+                                      feature_bits[i].feature_name),
+                       sep = ", ";
                        mask &= ~feature_bits[i].mask;
+                       size = sizeof(features) - (cp - features);
                }
        }
-       if (mask) {
-               /* print unknown features as a hex value: */
-               if (sep)
-                       *cp++ = sep;
-               sprintf(cp, " 0x%lx", mask);
+       if (mask && size > 1) {
+               /* print unknown features as a hex value */
+               snprintf(cp, size, "%s0x%lx", sep, mask);
        }
 
        proc_freq = cpufreq_quick_get(cpunum);
@@ -559,29 +695,32 @@ show_cpuinfo (struct seq_file *m, void *v)
                   "processor  : %d\n"
                   "vendor     : %s\n"
                   "arch       : IA-64\n"
-                  "family     : %s\n"
+                  "family     : %u\n"
                   "model      : %u\n"
+                  "model name : %s\n"
                   "revision   : %u\n"
                   "archrev    : %u\n"
-                  "features   :%s\n"   /* don't change this---it _is_ right! */
+                  "features   : %s\n"
                   "cpu number : %lu\n"
                   "cpu regs   : %u\n"
-                  "cpu MHz    : %lu.%06lu\n"
+                  "cpu MHz    : %lu.%03lu\n"
                   "itc MHz    : %lu.%06lu\n"
                   "BogoMIPS   : %lu.%02lu\n",
-                  cpunum, c->vendor, family, c->model, c->revision, c->archrev,
+                  cpunum, c->vendor, c->family, c->model,
+                  c->model_name, c->revision, c->archrev,
                   features, c->ppn, c->number,
                   proc_freq / 1000, proc_freq % 1000,
                   c->itc_freq / 1000000, c->itc_freq % 1000000,
                   lpj*HZ/500000, (lpj*HZ/5000) % 100);
 #ifdef CONFIG_SMP
        seq_printf(m, "siblings   : %u\n", cpus_weight(cpu_core_map[cpunum]));
+       if (c->socket_id != -1)
+               seq_printf(m, "physical id: %u\n", c->socket_id);
        if (c->threads_per_core > 1 || c->cores_per_socket > 1)
                seq_printf(m,
-                          "physical id: %u\n"
-                          "core id    : %u\n"
-                          "thread id  : %u\n",
-                          c->socket_id, c->core_id, c->thread_id);
+                          "core id    : %u\n"
+                          "thread id  : %u\n",
+                          c->core_id, c->thread_id);
 #endif
        seq_printf(m,"\n");
 
@@ -592,10 +731,10 @@ static void *
 c_start (struct seq_file *m, loff_t *pos)
 {
 #ifdef CONFIG_SMP
-       while (*pos < NR_CPUS && !cpu_isset(*pos, cpu_online_map))
+       while (*pos < nr_cpu_ids && !cpu_online(*pos))
                ++*pos;
 #endif
-       return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
+       return *pos < nr_cpu_ids ? cpu_data(*pos) : NULL;
 }
 
 static void *
@@ -610,14 +749,47 @@ c_stop (struct seq_file *m, void *v)
 {
 }
 
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
        .start =        c_start,
        .next =         c_next,
        .stop =         c_stop,
        .show =         show_cpuinfo
 };
 
-void
+#define MAX_BRANDS     8
+static char brandname[MAX_BRANDS][128];
+
+static char * __cpuinit
+get_model_name(__u8 family, __u8 model)
+{
+       static int overflow;
+       char brand[128];
+       int i;
+
+       memcpy(brand, "Unknown", 8);
+       if (ia64_pal_get_brand_info(brand)) {
+               if (family == 0x7)
+                       memcpy(brand, "Merced", 7);
+               else if (family == 0x1f) switch (model) {
+                       case 0: memcpy(brand, "McKinley", 9); break;
+                       case 1: memcpy(brand, "Madison", 8); break;
+                       case 2: memcpy(brand, "Madison up to 9M cache", 23); break;
+               }
+       }
+       for (i = 0; i < MAX_BRANDS; i++)
+               if (strcmp(brandname[i], brand) == 0)
+                       return brandname[i];
+       for (i = 0; i < MAX_BRANDS; i++)
+               if (brandname[i][0] == '\0')
+                       return strcpy(brandname[i], brand);
+       if (overflow++ == 0)
+               printk(KERN_ERR
+                      "%s: Table overflow. Some processor model information will be missing\n",
+                      __func__);
+       return "Unknown";
+}
+
+static void __cpuinit
 identify_cpu (struct cpuinfo_ia64 *c)
 {
        union {
@@ -646,7 +818,6 @@ identify_cpu (struct cpuinfo_ia64 *c)
        pal_status_t status;
        unsigned long impl_va_msb = 50, phys_addr_size = 44;    /* Itanium defaults */
        int i;
-
        for (i = 0; i < 5; ++i)
                cpuid.bits[i] = ia64_get_cpuid(i);
 
@@ -655,12 +826,15 @@ identify_cpu (struct cpuinfo_ia64 *c)
        c->cpu = smp_processor_id();
 
        /* below default values will be overwritten  by identify_siblings() 
-        * for Multi-Threading/Multi-Core capable cpu's
+        * for Multi-Threading/Multi-Core capable CPUs
         */
        c->threads_per_core = c->cores_per_socket = c->num_log = 1;
        c->socket_id = -1;
 
        identify_siblings(c);
+
+       if (c->threads_per_core > smp_num_siblings)
+               smp_num_siblings = c->threads_per_core;
 #endif
        c->ppn = cpuid.field.ppn;
        c->number = cpuid.field.number;
@@ -669,6 +843,7 @@ identify_cpu (struct cpuinfo_ia64 *c)
        c->family = cpuid.field.family;
        c->archrev = cpuid.field.archrev;
        c->features = cpuid.field.features;
+       c->model_name = get_model_name(c->family, c->model);
 
        status = ia64_pal_vm_summary(&vm1, &vm2);
        if (status == PAL_STATUS_SUCCESS) {
@@ -679,60 +854,63 @@ identify_cpu (struct cpuinfo_ia64 *c)
        c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
 }
 
-void
-setup_per_cpu_areas (void)
-{
-       /* start_kernel() requires this... */
-}
-
 /*
- * Calculate the max. cache line size.
+ * Do the following calculations:
  *
- * In addition, the minimum of the i-cache stride sizes is calculated for
- * "flush_icache_range()".
+ * 1. the max. cache line size.
+ * 2. the minimum of the i-cache stride sizes for "flush_icache_range()".
+ * 3. the minimum of the cache stride sizes for "clflush_cache_range()".
  */
-static void
-get_max_cacheline_size (void)
+static void __cpuinit
+get_cache_info(void)
 {
        unsigned long line_size, max = 1;
-       u64 l, levels, unique_caches;
-        pal_cache_config_info_t cci;
-        s64 status;
+       unsigned long l, levels, unique_caches;
+       pal_cache_config_info_t cci;
+       long status;
 
         status = ia64_pal_cache_summary(&levels, &unique_caches);
         if (status != 0) {
                 printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n",
-                       __FUNCTION__, status);
+                       __func__, status);
                 max = SMP_CACHE_BYTES;
                /* Safest setup for "flush_icache_range()" */
                ia64_i_cache_stride_shift = I_CACHE_STRIDE_SHIFT;
+               /* Safest setup for "clflush_cache_range()" */
+               ia64_cache_stride_shift = CACHE_STRIDE_SHIFT;
                goto out;
         }
 
        for (l = 0; l < levels; ++l) {
-               status = ia64_pal_cache_config_info(l, /* cache_type (data_or_unified)= */ 2,
-                                                   &cci);
+               /* cache_type (data_or_unified)=2 */
+               status = ia64_pal_cache_config_info(l, 2, &cci);
                if (status != 0) {
-                       printk(KERN_ERR
-                              "%s: ia64_pal_cache_config_info(l=%lu, 2) failed (status=%ld)\n",
-                              __FUNCTION__, l, status);
+                       printk(KERN_ERR "%s: ia64_pal_cache_config_info"
+                               "(l=%lu, 2) failed (status=%ld)\n",
+                               __func__, l, status);
                        max = SMP_CACHE_BYTES;
                        /* The safest setup for "flush_icache_range()" */
                        cci.pcci_stride = I_CACHE_STRIDE_SHIFT;
+                       /* The safest setup for "clflush_cache_range()" */
+                       ia64_cache_stride_shift = CACHE_STRIDE_SHIFT;
                        cci.pcci_unified = 1;
+               } else {
+                       if (cci.pcci_stride < ia64_cache_stride_shift)
+                               ia64_cache_stride_shift = cci.pcci_stride;
+
+                       line_size = 1 << cci.pcci_line_size;
+                       if (line_size > max)
+                               max = line_size;
                }
-               line_size = 1 << cci.pcci_line_size;
-               if (line_size > max)
-                       max = line_size;
+
                if (!cci.pcci_unified) {
-                       status = ia64_pal_cache_config_info(l,
-                                                   /* cache_type (instruction)= */ 1,
-                                                   &cci);
+                       /* cache_type (instruction)=1*/
+                       status = ia64_pal_cache_config_info(l, 1, &cci);
                        if (status != 0) {
-                               printk(KERN_ERR
-                               "%s: ia64_pal_cache_config_info(l=%lu, 1) failed (status=%ld)\n",
-                                       __FUNCTION__, l, status);
-                               /* The safest setup for "flush_icache_range()" */
+                               printk(KERN_ERR "%s: ia64_pal_cache_config_info"
+                                       "(l=%lu, 1) failed (status=%ld)\n",
+                                       __func__, l, status);
+                               /* The safest setup for flush_icache_range() */
                                cci.pcci_stride = I_CACHE_STRIDE_SHIFT;
                        }
                }
@@ -748,10 +926,11 @@ get_max_cacheline_size (void)
  * cpu_init() initializes state that is per-CPU.  This function acts
  * as a 'CPU state barrier', nothing should get across.
  */
-void
+void __cpuinit
 cpu_init (void)
 {
-       extern void __devinit ia64_mmu_init (void *);
+       extern void __cpuinit ia64_mmu_init (void *);
+       static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG;
        unsigned long num_phys_stacked;
        pal_vm_info_2_u_t vmi;
        unsigned int max_ctx;
@@ -759,16 +938,28 @@ cpu_init (void)
        void *cpu_data;
 
        cpu_data = per_cpu_init();
-
+#ifdef CONFIG_SMP
        /*
-        * We set ar.k3 so that assembly code in MCA handler can compute
-        * physical addresses of per cpu variables with a simple:
-        *   phys = ar.k3 + &per_cpu_var
+        * insert boot cpu into sibling and core mapes
+        * (must be done after per_cpu area is setup)
         */
-       ia64_set_kr(IA64_KR_PER_CPU_DATA,
-                   ia64_tpa(cpu_data) - (long) __per_cpu_start);
+       if (smp_processor_id() == 0) {
+               cpu_set(0, per_cpu(cpu_sibling_map, 0));
+               cpu_set(0, cpu_core_map[0]);
+       } else {
+               /*
+                * Set ar.k3 so that assembly code in MCA handler can compute
+                * physical addresses of per cpu variables with a simple:
+                *   phys = ar.k3 + &per_cpu_var
+                * and the alt-dtlb-miss handler can set per-cpu mapping into
+                * the TLB when needed. head.S already did this for cpu0.
+                */
+               ia64_set_kr(IA64_KR_PER_CPU_DATA,
+                           ia64_tpa(cpu_data) - (long) __per_cpu_start);
+       }
+#endif
 
-       get_max_cacheline_size();
+       get_cache_info();
 
        /*
         * We can't pass "local_cpu_data" to identify_cpu() because we haven't called
@@ -776,7 +967,7 @@ cpu_init (void)
         * depends on the data returned by identify_cpu().  We break the dependency by
         * accessing cpu_data() through the canonical per-CPU address.
         */
-       cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(cpu_info) - __per_cpu_start);
+       cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(ia64_cpu_info) - __per_cpu_start);
        identify_cpu(cpu_info);
 
 #ifdef CONFIG_MCKINLEY
@@ -794,7 +985,7 @@ cpu_init (void)
 #endif
 
        /* Clear the stack memory reserved for pt_regs: */
-       memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
+       memset(task_pt_regs(current), 0, sizeof(struct pt_regs));
 
        ia64_set_kr(IA64_KR_FPU_OWNER, 0);
 
@@ -820,8 +1011,7 @@ cpu_init (void)
                                        | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC));
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
-       if (current->mm)
-               BUG();
+       BUG_ON(current->mm);
 
        ia64_mmu_init(ia64_imva(cpu_data));
        ia64_mca_cpu_init(ia64_imva(cpu_data));
@@ -830,7 +1020,7 @@ cpu_init (void)
        ia32_cpu_init();
 #endif
 
-       /* Clear ITC to eliminiate sched_clock() overflows in human time.  */
+       /* Clear ITC to eliminate sched_clock() overflows in human time.  */
        ia64_set_itc(0);
 
        /* disable all local interrupt sources: */
@@ -842,14 +1032,20 @@ cpu_init (void)
 
        /* clear TPR & XTP to enable all interrupt classes: */
        ia64_setreg(_IA64_REG_CR_TPR, 0);
+
+       /* Clear any pending interrupts left by SAL/EFI */
+       while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
+               ia64_eoi();
+
 #ifdef CONFIG_SMP
        normal_xtp();
 #endif
 
        /* set ia64_ctx.max_rid to the maximum RID that is supported by all CPUs: */
-       if (ia64_pal_vm_summary(NULL, &vmi) == 0)
+       if (ia64_pal_vm_summary(NULL, &vmi) == 0) {
                max_ctx = (1U << (vmi.pal_vm_info_2_s.rid_size - 3)) - 1;
-       else {
+               setup_ptcg_sem(vmi.pal_vm_info_2_s.max_purges, NPTCG_FROM_PAL);
+       } else {
                printk(KERN_WARNING "cpu_init: PAL VM summary failed, assuming 18 RID bits\n");
                max_ctx = (1U << 15) - 1;       /* use architected minimum */
        }
@@ -865,14 +1061,24 @@ cpu_init (void)
                num_phys_stacked = 96;
        }
        /* size of physical stacked register partition plus 8 bytes: */
-       __get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8;
+       if (num_phys_stacked > max_num_phys_stacked) {
+               ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8);
+               max_num_phys_stacked = num_phys_stacked;
+       }
        platform_cpu_init();
        pm_idle = default_idle;
 }
 
-void
+void __init
 check_bugs (void)
 {
        ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles,
                               (unsigned long) __end___mckinley_e9_bundles);
 }
+
+static int __init run_dmi_scan(void)
+{
+       dmi_scan_machine();
+       return 0;
+}
+core_initcall(run_dmi_scan);