*
* Nov 2001 Dave Jones <davej@suse.de>
* Forked from i386 setup code.
+ *
+ * $Id$
*/
/*
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
-#include <linux/screen_info.h>
+#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/initrd.h>
#include <linux/highmem.h>
#include <linux/cpufreq.h>
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
#include <asm/mtrr.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
#include <asm/mach_apic.h>
#include <asm/numa.h>
+#include <asm/swiotlb.h>
#include <asm/sections.h>
-#include <asm/dmi.h>
+#include <asm/gart-mapping.h>
/*
* Machine setup..
*/
struct cpuinfo_x86 boot_cpu_data __read_mostly;
-EXPORT_SYMBOL(boot_cpu_data);
unsigned long mmu_cr4_features;
unsigned long saved_video_mode;
-/*
- * Early DMI memory
- */
-int dmi_alloc_index;
-char dmi_alloc_data[DMI_MAX_DATA];
-
/*
* Setup options
*/
struct screen_info screen_info;
-EXPORT_SYMBOL(screen_info);
struct sys_desc_table_struct {
unsigned short length;
unsigned char table[0];
};
struct edid_info edid_info;
-EXPORT_SYMBOL_GPL(edid_info);
struct e820map e820;
extern int root_mountflags;
}
}
-/* Check for full argument with no trailing characters */
-static int fullarg(char *p, char *arg)
-{
- int l = strlen(arg);
- return !memcmp(p, arg, l) && (p[l] == 0 || isspace(p[l]));
-}
-
static __init void parse_cmdline_early (char ** cmdline_p)
{
char c = ' ', *to = command_line, *from = COMMAND_LINE;
#endif
#ifdef CONFIG_ACPI
/* "acpi=off" disables both ACPI table parsing and interpreter init */
- if (fullarg(from,"acpi=off"))
+ if (!memcmp(from, "acpi=off", 8))
disable_acpi();
- if (fullarg(from, "acpi=force")) {
+ if (!memcmp(from, "acpi=force", 10)) {
/* add later when we do DMI horrors: */
acpi_force = 1;
acpi_disabled = 0;
/* acpi=ht just means: do ACPI MADT parsing
at bootup, but don't enable the full ACPI interpreter */
- if (fullarg(from, "acpi=ht")) {
+ if (!memcmp(from, "acpi=ht", 7)) {
if (!acpi_force)
disable_acpi();
acpi_ht = 1;
}
- else if (fullarg(from, "pci=noacpi"))
+ else if (!memcmp(from, "pci=noacpi", 10))
acpi_disable_pci();
- else if (fullarg(from, "acpi=noirq"))
+ else if (!memcmp(from, "acpi=noirq", 10))
acpi_noirq_set();
- else if (fullarg(from, "acpi_sci=edge"))
+ else if (!memcmp(from, "acpi_sci=edge", 13))
acpi_sci_flags.trigger = 1;
- else if (fullarg(from, "acpi_sci=level"))
+ else if (!memcmp(from, "acpi_sci=level", 14))
acpi_sci_flags.trigger = 3;
- else if (fullarg(from, "acpi_sci=high"))
+ else if (!memcmp(from, "acpi_sci=high", 13))
acpi_sci_flags.polarity = 1;
- else if (fullarg(from, "acpi_sci=low"))
+ else if (!memcmp(from, "acpi_sci=low", 12))
acpi_sci_flags.polarity = 3;
/* acpi=strict disables out-of-spec workarounds */
- else if (fullarg(from, "acpi=strict")) {
+ else if (!memcmp(from, "acpi=strict", 11)) {
acpi_strict = 1;
}
#ifdef CONFIG_X86_IO_APIC
- else if (fullarg(from, "acpi_skip_timer_override"))
+ else if (!memcmp(from, "acpi_skip_timer_override", 24))
acpi_skip_timer_override = 1;
#endif
#endif
- if (fullarg(from, "disable_timer_pin_1"))
+ if (!memcmp(from, "disable_timer_pin_1", 19))
disable_timer_pin_1 = 1;
- if (fullarg(from, "enable_timer_pin_1"))
+ if (!memcmp(from, "enable_timer_pin_1", 18))
disable_timer_pin_1 = -1;
- if (fullarg(from, "nolapic") || fullarg(from, "disableapic")) {
- clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+ if (!memcmp(from, "nolapic", 7) ||
+ !memcmp(from, "disableapic", 11))
disable_apic = 1;
- }
- if (fullarg(from, "noapic"))
+ /* Don't confuse with noapictimer */
+ if (!memcmp(from, "noapic", 6) &&
+ (from[6] == ' ' || from[6] == 0))
skip_ioapic_setup = 1;
- if (fullarg(from,"apic")) {
+ /* Make sure to not confuse with apic= */
+ if (!memcmp(from, "apic", 4) &&
+ (from[4] == ' ' || from[4] == 0)) {
skip_ioapic_setup = 0;
ioapic_force = 1;
}
iommu_setup(from+6);
}
- if (fullarg(from,"oops=panic"))
+ if (!memcmp(from,"oops=panic", 10))
panic_on_oops = 1;
if (!memcmp(from, "noexec=", 7))
}
#endif
+/* Use inline assembly to define this because the nops are defined
+ as inline assembly strings in the include files and we cannot
+ get them easily into strings. */
+asm("\t.data\nk8nops: "
+ K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
+ K8_NOP7 K8_NOP8);
+
+extern unsigned char k8nops[];
+static unsigned char *k8_nops[ASM_NOP_MAX+1] = {
+ NULL,
+ k8nops,
+ k8nops + 1,
+ k8nops + 1 + 2,
+ k8nops + 1 + 2 + 3,
+ k8nops + 1 + 2 + 3 + 4,
+ k8nops + 1 + 2 + 3 + 4 + 5,
+ k8nops + 1 + 2 + 3 + 4 + 5 + 6,
+ k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+};
+
+extern char __vsyscall_0;
+
+/* Replace instructions with better alternatives for this CPU type.
+
+ This runs before SMP is initialized to avoid SMP problems with
+ self modifying code. This implies that assymetric systems where
+ APs have less capabilities than the boot processor are not handled.
+ In this case boot with "noreplacement". */
+void apply_alternatives(void *start, void *end)
+{
+ struct alt_instr *a;
+ int diff, i, k;
+ for (a = start; (void *)a < end; a++) {
+ u8 *instr;
+
+ if (!boot_cpu_has(a->cpuid))
+ continue;
+
+ BUG_ON(a->replacementlen > a->instrlen);
+ instr = a->instr;
+ /* vsyscall code is not mapped yet. resolve it manually. */
+ if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END)
+ instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0));
+ __inline_memcpy(instr, a->replacement, a->replacementlen);
+ diff = a->instrlen - a->replacementlen;
+
+ /* Pad the rest with nops */
+ for (i = a->replacementlen; diff > 0; diff -= k, i += k) {
+ k = diff;
+ if (k > ASM_NOP_MAX)
+ k = ASM_NOP_MAX;
+ __inline_memcpy(instr + i, k8_nops[k], k);
+ }
+ }
+}
+
+static int no_replacement __initdata = 0;
+
+void __init alternative_instructions(void)
+{
+ extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+ if (no_replacement)
+ return;
+ apply_alternatives(__alt_instructions, __alt_instructions_end);
+}
+
+static int __init noreplacement_setup(char *s)
+{
+ no_replacement = 1;
+ return 0;
+}
+
+__setup("noreplacement", noreplacement_setup);
+
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
struct edd edd;
#ifdef CONFIG_EDD_MODULE
#endif
#define EBDA_ADDR_POINTER 0x40E
-
-unsigned __initdata ebda_addr;
-unsigned __initdata ebda_size;
-
-static void discover_ebda(void)
+static void __init reserve_ebda_region(void)
{
- /*
+ unsigned int addr;
+ /**
* there is a real-mode segmented pointer pointing to the
* 4K EBDA area at 0x40E
*/
- ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER;
- ebda_addr <<= 4;
-
- ebda_size = *(unsigned short *)(unsigned long)ebda_addr;
-
- /* Round EBDA up to pages */
- if (ebda_size == 0)
- ebda_size = 1;
- ebda_size <<= 10;
- ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
- if (ebda_size > 64*1024)
- ebda_size = 64*1024;
+ addr = *(unsigned short *)phys_to_virt(EBDA_ADDR_POINTER);
+ addr <<= 4;
+ if (addr)
+ reserve_bootmem_generic(addr, PAGE_SIZE);
}
void __init setup_arch(char **cmdline_p)
{
+ unsigned long kernel_end;
+
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
screen_info = SCREEN_INFO;
edid_info = EDID_INFO;
* we are rounding upwards:
*/
end_pfn = e820_end_of_ram();
- num_physpages = end_pfn; /* for pfn_valid */
check_efer();
- discover_ebda();
-
init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
- dmi_scan_machine();
-
zap_low_mappings(0);
#ifdef CONFIG_ACPI
(table_end - table_start) << PAGE_SHIFT);
/* reserve kernel */
- reserve_bootmem_generic(__pa_symbol(&_text),
- __pa_symbol(&_end) - __pa_symbol(&_text));
+ kernel_end = round_up(__pa_symbol(&_end),PAGE_SIZE);
+ reserve_bootmem_generic(HIGH_MEMORY, kernel_end - HIGH_MEMORY);
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
reserve_bootmem_generic(0, PAGE_SIZE);
/* reserve ebda region */
- if (ebda_addr)
- reserve_bootmem_generic(ebda_addr, ebda_size);
+ reserve_ebda_region();
#ifdef CONFIG_SMP
/*
#endif
#ifdef CONFIG_KEXEC
if (crashk_res.start != crashk_res.end) {
- reserve_bootmem_generic(crashk_res.start,
+ reserve_bootmem(crashk_res.start,
crashk_res.end - crashk_res.start + 1);
}
#endif
check_ioapic();
- /*
- * set this early, so we dont allocate cpu0
- * if MADT list doesnt list BSP first
- * mpparse.c/MP_processor_info() allocates logical cpu numbers.
- */
- cpu_set(0, cpu_present_map);
#ifdef CONFIG_ACPI
/*
* Read APIC and some other early information from ACPI tables.
*/
probe_roms();
e820_reserve_resources();
- e820_mark_nosave_regions();
request_resource(&iomem_resource, &video_ram_resource);
e820_setup_gap();
+#ifdef CONFIG_GART_IOMMU
+ iommu_hole_init();
+#endif
+
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
+ int cpu = smp_processor_id();
unsigned bits;
#ifdef CONFIG_NUMA
- int cpu = smp_processor_id();
int node = 0;
- unsigned apicid = hard_smp_processor_id();
+ unsigned apicid = phys_proc_id[cpu];
#endif
- unsigned ecx = cpuid_ecx(0x80000008);
-
- c->x86_max_cores = (ecx & 0xff) + 1;
- /* CPU telling us the core id bits shift? */
- bits = (ecx >> 12) & 0xF;
-
- /* Otherwise recompute */
- if (bits == 0) {
- while ((1 << bits) < c->x86_max_cores)
- bits++;
- }
+ bits = 0;
+ while ((1 << bits) < c->x86_max_cores)
+ bits++;
/* Low order bits define the core id (index of core in socket) */
- c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
+ cpu_core_id[cpu] = phys_proc_id[cpu] & ((1 << bits)-1);
/* Convert the APIC ID into the socket ID */
- c->phys_proc_id = phys_pkg_id(bits);
+ phys_proc_id[cpu] >>= bits;
#ifdef CONFIG_NUMA
- node = c->phys_proc_id;
+ node = phys_proc_id[cpu];
if (apicid_to_node[apicid] != NUMA_NO_NODE)
node = apicid_to_node[apicid];
if (!node_online(node)) {
but in the same order as the HT nodeids.
If that doesn't result in a usable node fall back to the
path for the previous case. */
- int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits);
+ int ht_nodeid = apicid - (phys_proc_id[0] << bits);
if (ht_nodeid >= 0 &&
apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
node = apicid_to_node[ht_nodeid];
}
numa_set_node(cpu, node);
- printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+ printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
+ cpu, c->x86_max_cores, node, cpu_core_id[cpu]);
#endif
#endif
}
-static void __init init_amd(struct cpuinfo_x86 *c)
+static int __init init_amd(struct cpuinfo_x86 *c)
{
+ int r;
unsigned level;
#ifdef CONFIG_SMP
if (c->x86 >= 6)
set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
- level = get_model_name(c);
- if (!level) {
+ r = get_model_name(c);
+ if (!r) {
switch (c->x86) {
case 15:
/* Should distinguish Models here, but this is only
if (c->x86_power & (1<<8))
set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
- /* Multi core CPU? */
- if (c->extended_cpuid_level >= 0x80000008)
+ if (c->extended_cpuid_level >= 0x80000008) {
+ c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+ if (c->x86_max_cores & (c->x86_max_cores - 1))
+ c->x86_max_cores = 1;
+
amd_detect_cmp(c);
+ }
- /* Fix cpuid4 emulation for more */
- num_cache_leaves = 3;
+ return r;
}
static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
#ifdef CONFIG_SMP
u32 eax, ebx, ecx, edx;
int index_msb, core_bits;
+ int cpu = smp_processor_id();
cpuid(1, &eax, &ebx, &ecx, &edx);
+ c->apicid = phys_pkg_id(0);
- if (!cpu_has(c, X86_FEATURE_HT))
+ if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
return;
- if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
- goto out;
smp_num_siblings = (ebx & 0xff0000) >> 16;
}
index_msb = get_count_order(smp_num_siblings);
- c->phys_proc_id = phys_pkg_id(index_msb);
+ phys_proc_id[cpu] = phys_pkg_id(index_msb);
+
+ printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
+ phys_proc_id[cpu]);
smp_num_siblings = smp_num_siblings / c->x86_max_cores;
core_bits = get_count_order(c->x86_max_cores);
- c->cpu_core_id = phys_pkg_id(index_msb) &
+ cpu_core_id[cpu] = phys_pkg_id(index_msb) &
((1 << core_bits) - 1);
- }
-out:
- if ((c->x86_max_cores * smp_num_siblings) > 1) {
- printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
- printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id);
- }
+ if (c->x86_max_cores > 1)
+ printk(KERN_INFO "CPU: Processor Core ID: %d\n",
+ cpu_core_id[cpu]);
+ }
#endif
}
*/
static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
{
- unsigned int eax, t;
+ unsigned int eax;
if (c->cpuid_level < 4)
return 1;
- cpuid_count(4, 0, &eax, &t, &t, &t);
+ __asm__("cpuid"
+ : "=a" (eax)
+ : "0" (4), "c" (0)
+ : "bx", "dx");
if (eax & 0x1f)
return ((eax >> 26) + 1);
#ifdef CONFIG_NUMA
unsigned node;
int cpu = smp_processor_id();
- int apicid = hard_smp_processor_id();
/* Don't do the funky fallback heuristics the AMD version employs
for now. */
- node = apicid_to_node[apicid];
+ node = apicid_to_node[hard_smp_processor_id()];
if (node == NUMA_NO_NODE)
- node = first_node(node_online_map);
+ node = 0;
numa_set_node(cpu, node);
if (acpi_numa > 0)
- printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+ printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node);
#endif
}
unsigned n;
init_intel_cacheinfo(c);
- if (c->cpuid_level > 9 ) {
- unsigned eax = cpuid_eax(10);
- /* Check for version and the number of counters */
- if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
- set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
- }
-
n = c->extended_cpuid_level;
if (n >= 0x80000008) {
unsigned eax = cpuid_eax(0x80000008);
if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
(c->x86 == 0x6 && c->x86_model >= 0x0e))
set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
- set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+ if (c->x86 == 15)
+ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+ else
+ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
c->x86_max_cores = intel_num_cpu_cores(c);
srat_detect_node();
}
#ifdef CONFIG_SMP
- c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
+ phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
#endif
}
c->x86_capability[2] = cpuid_edx(0x80860001);
}
- c->apicid = phys_pkg_id(0);
-
/*
* Vendor-specific initialization. In this section we
* canonicalize the feature flags, meaning if there are
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
- NULL, "fxsr_opt", NULL, "rdtscp", NULL, "lm", "3dnowext", "3dnow",
+ NULL, "fxsr_opt", "rdtscp", NULL, NULL, "lm", "3dnowext", "3dnow",
/* Transmeta-defined */
"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
/* Other (Linux-defined) */
"cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
"constant_tsc", NULL, NULL,
- "up", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Intel-defined (#2) */
- "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", NULL, "est",
"tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
#ifdef CONFIG_SMP
if (smp_num_siblings * c->x86_max_cores > 1) {
int cpu = c - cpu_data;
- seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
+ seq_printf(m, "physical id\t: %d\n", phys_proc_id[cpu]);
seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu]));
- seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
+ seq_printf(m, "core id\t\t: %d\n", cpu_core_id[cpu]);
seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
}
#endif
{
int i;
for ( i = 0 ; i < 32*NCAPINTS ; i++ )
- if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
+ if ( test_bit(i, &c->x86_capability) &&
+ x86_cap_flags[i] != NULL )
seq_printf(m, " %s", x86_cap_flags[i]);
}
.show = show_cpuinfo,
};
-#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE)
-#include <linux/platform_device.h>
-static __init int add_pcspkr(void)
+static int __init run_dmi_scan(void)
{
- struct platform_device *pd;
- int ret;
-
- pd = platform_device_alloc("pcspkr", -1);
- if (!pd)
- return -ENOMEM;
-
- ret = platform_device_add(pd);
- if (ret)
- platform_device_put(pd);
-
- return ret;
+ dmi_scan_machine();
+ return 0;
}
-device_initcall(add_pcspkr);
-#endif
+core_initcall(run_dmi_scan);
+