*
* 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 <asm/setup.h>
#include <asm/mach_apic.h>
#include <asm/numa.h>
+#include <asm/swiotlb.h>
#include <asm/sections.h>
+#include <asm/gart-mapping.h>
#include <asm/dmi.h>
/*
*/
struct cpuinfo_x86 boot_cpu_data __read_mostly;
-EXPORT_SYMBOL(boot_cpu_data);
unsigned long mmu_cr4_features;
* 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;
}
#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 1;
+}
+
+__setup("noreplacement", noreplacement_setup);
+
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
struct edd edd;
#ifdef CONFIG_EDD_MODULE
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;
(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,
#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
*/
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();
#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] = phys_pkg_id(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/%x(%d) -> Node %d -> Core %d\n",
+ cpu, apicid, 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;
+
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);
- 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);
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);
- if (c->x86 == 15)
- set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
- else
- clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+ set_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
}
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,
#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