* 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/initrd.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/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/unistd.h>
#include <asm/system.h>
+#ifdef CONFIG_XEN
+#include <asm/hypervisor.h>
+#endif
+#include <linux/dma-mapping.h>
#if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
# error "struct cpuinfo_ia64 too big!"
EXPORT_SYMBOL(__per_cpu_offset);
#endif
+#ifdef CONFIG_XEN
+static int
+xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ HYPERVISOR_shutdown(SHUTDOWN_crash);
+ /* we're never actually going to get here... */
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xen_panic_block = {
+ .notifier_call = xen_panic_event,
+ .next = NULL,
+ .priority = 0 /* try to go last */
+};
+#endif
+
extern void ia64_setup_printk_clock(void);
DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
return 0;
}
+static int __init
+rsvd_region_cmp(struct rsvd_region *lhs, struct rsvd_region *rhs)
+{
+ if (lhs->start > rhs->start)
+ return 1;
+ if (lhs->start < rhs->start)
+ return -1;
+
+ if (lhs->end > rhs->end)
+ return 1;
+ if (lhs->end < rhs->end)
+ return -1;
+
+ return 0;
+}
+
static void __init
sort_regions (struct rsvd_region *rsvd_region, int max)
{
+ int num = max;
int j;
/* simple bubble sorting */
while (max--) {
for (j = 0; j < max; ++j) {
- if (rsvd_region[j].start > rsvd_region[j+1].start) {
+ if (rsvd_region_cmp(&rsvd_region[j],
+ &rsvd_region[j + 1]) > 0) {
struct rsvd_region tmp;
tmp = rsvd_region[j];
rsvd_region[j] = rsvd_region[j + 1];
}
}
}
+
+ for (j = 0; j < num - 1; j++) {
+ int k;
+ unsigned long start = rsvd_region[j].start;
+ unsigned long end = rsvd_region[j].end;
+ int collapsed;
+
+ for (k = j + 1; k < num; k++) {
+ BUG_ON(start > rsvd_region[k].start);
+ if (end < rsvd_region[k].start) {
+ k--;
+ break;
+ }
+ end = max(end, rsvd_region[k].end);
+ }
+ if (k == num)
+ k--;
+ rsvd_region[j].end = end;
+ collapsed = k - j;
+ num -= collapsed;
+ for (k = j + 1; k < num; k++) {
+ rsvd_region[k] = rsvd_region[k + collapsed];
+ }
+ }
+
+ num_rsvd_regions = num;
+ for (j = 0; j < num; j++) {
+ printk("rsvd_region[%d]: [0x%016lx, 0x%06lx)\n",
+ j, rsvd_region[j].start, rsvd_region[j].end);
+ }
}
/*
rsvd_region[n].end = (unsigned long) ia64_imva(_end);
n++;
+#ifdef CONFIG_XEN
+ if (is_running_on_xen()) {
+ rsvd_region[n].start = (unsigned long)__va((HYPERVISOR_shared_info->arch.start_info_pfn << PAGE_SHIFT));
+ rsvd_region[n].end = rsvd_region[n].start + PAGE_SIZE;
+ n++;
+ }
+#endif
+
#ifdef CONFIG_BLK_DEV_INITRD
if (ia64_boot_param->initrd_start) {
rsvd_region[n].start = (unsigned long)__va(ia64_boot_param->initrd_start);
efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
n++;
+#ifdef CONFIG_KEXEC
+ /* crashkernel=size@offset specifies the size to reserve for a crash
+ * kernel. If offset is 0, then it is determined automatically.
+ * By reserving this memory we guarantee that linux never set's it
+ * up as a DMA target.Useful for holding code to do something
+ * appropriate after a kernel panic.
+ */
+ {
+ char *from = strstr(saved_command_line, "crashkernel=");
+ unsigned long base, size;
+ if (from) {
+ size = memparse(from + 12, &from);
+ if (*from == '@')
+ base = memparse(from+1, &from);
+ else
+ base = 0;
+ if (size) {
+ if (!base) {
+ sort_regions(rsvd_region, n);
+ base = kdump_find_rsvd_region(size,
+ rsvd_region, n);
+ }
+ if (base != ~0UL) {
+ 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);
+ }
+#endif
/* 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
*
{
int earlycons = 0;
+#ifdef CONFIG_XEN
+#ifndef CONFIG_IA64_HP_SIM
+ if (is_running_on_xen()) {
+ extern struct console hpsim_cons;
+ hpsim_cons.flags |= CON_BOOT;
+ register_console(&hpsim_cons);
+ earlycons++;
+ }
+#endif
+#endif
#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
{
extern int sn_serial_console_early_setup(void);
}
early_param("nomca", setup_nomca);
+#ifdef CONFIG_PROC_VMCORE
+/* 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);
+#endif /* CONFIG_PROC_VMCORE */
+
void __init
setup_arch (char **cmdline_p)
{
unw_init();
+#ifdef CONFIG_XEN
+ if (is_running_on_xen()) {
+ setup_xen_features();
+ /* Register a call for panic conditions. */
+ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
+ }
+#endif
+
ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
*cmdline_p = __va(ia64_boot_param->command_line);
cpu_init(); /* initialize the bootstrap CPU */
mmu_context_init(); /* initialize context_id bitmap */
+ check_sal_cache_flush();
+
#ifdef CONFIG_ACPI
acpi_boot_init();
#endif
conswitchp = &vga_con;
# endif
}
+#ifdef CONFIG_XEN
+ if (is_running_on_xen()) {
+ shared_info_t *s = HYPERVISOR_shared_info;
+
+ xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT);
+
+ printk("Running on Xen! start_info_pfn=0x%lx nr_pages=%ld "
+ "flags=0x%x\n", s->arch.start_info_pfn,
+ xen_start_info->nr_pages, xen_start_info->flags);
+
+ if (!is_initial_xendomain()) {
+#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = NULL;
+#endif
+ }
+ }
+#endif
#endif
/* enable IA-64 Machine Check Abort Handling unless disabled */
platform_setup(cmdline_p);
paging_init();
+#ifdef CONFIG_XEN
+ contiguous_bitmap_init(max_pfn);
+#endif
}
/*
{ 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 long proc_freq;
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);
cp = features;
"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! */
"cpu MHz : %lu.%06lu\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,
.show = show_cpuinfo
};
+static char brandname[128];
+
+static char * __cpuinit
+get_model_name(__u8 family, __u8 model)
+{
+ char brand[128];
+
+ 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;
+ }
+ }
+ if (brandname[0] == '\0')
+ return strcpy(brandname, brand);
+ else if (strcmp(brandname, brand) == 0)
+ return brandname;
+ else
+ return kstrdup(brand, GFP_KERNEL);
+}
+
static void __cpuinit
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);
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) {
/* size of physical stacked register partition plus 8 bytes: */
__get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8;
platform_cpu_init();
+
+#ifdef CONFIG_XEN
+ /* Need to be moved into platform_cpu_init later */
+ if (is_running_on_xen()) {
+ extern void xen_smp_intr_init(void);
+ xen_smp_intr_init();
+ }
+#endif
+
pm_idle = default_idle;
}