2eaad1fddd
When there are a large number of processors in a system, there is an excessive amount of messages sent to the system console. It's estimated that with 4096 processors in a system, and the console baudrate set to 56K, the startup messages will take about 84 minutes to clear the serial port. This set of patches limits the number of repetitious messages which contain no additional information. Much of this information is obtainable from the /proc and /sysfs. Some of the messages are also sent to the kernel log buffer as KERN_DEBUG messages so dmesg can be used to examine more closely any details specific to a problem. The new cpu bootup sequence for system_state == SYSTEM_BOOTING: Booting Node 0, Processors #1 #2 #3 #4 #5 #6 #7 Ok. Booting Node 1, Processors #8 #9 #10 #11 #12 #13 #14 #15 Ok. ... Booting Node 3, Processors #56 #57 #58 #59 #60 #61 #62 #63 Ok. Brought up 64 CPUs After the system is running, a single line boot message is displayed when CPU's are hotplugged on: Booting Node %d Processor %d APIC 0x%x Status of the following lines: CPU: Physical Processor ID: printed once (for boot cpu) CPU: Processor Core ID: printed once (for boot cpu) CPU: Hyper-Threading is disabled printed once (for boot cpu) CPU: Thermal monitoring enabled printed once (for boot cpu) CPU %d/0x%x -> Node %d: removed CPU %d is now offline: only if system_state == RUNNING Initializing CPU#%d: KERN_DEBUG Signed-off-by: Mike Travis <travis@sgi.com> LKML-Reference: <4B219E28.8080601@sgi.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
141 lines
3.3 KiB
C
141 lines
3.3 KiB
C
/*
|
|
* Routines to indentify additional cpu features that are scattered in
|
|
* cpuid space.
|
|
*/
|
|
#include <linux/cpu.h>
|
|
|
|
#include <asm/pat.h>
|
|
#include <asm/processor.h>
|
|
|
|
#include <asm/apic.h>
|
|
|
|
struct cpuid_bit {
|
|
u16 feature;
|
|
u8 reg;
|
|
u8 bit;
|
|
u32 level;
|
|
};
|
|
|
|
enum cpuid_regs {
|
|
CR_EAX = 0,
|
|
CR_ECX,
|
|
CR_EDX,
|
|
CR_EBX
|
|
};
|
|
|
|
void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
|
|
{
|
|
u32 max_level;
|
|
u32 regs[4];
|
|
const struct cpuid_bit *cb;
|
|
|
|
static const struct cpuid_bit __cpuinitconst cpuid_bits[] = {
|
|
{ X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 },
|
|
{ X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006 },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
for (cb = cpuid_bits; cb->feature; cb++) {
|
|
|
|
/* Verify that the level is valid */
|
|
max_level = cpuid_eax(cb->level & 0xffff0000);
|
|
if (max_level < cb->level ||
|
|
max_level > (cb->level | 0xffff))
|
|
continue;
|
|
|
|
cpuid(cb->level, ®s[CR_EAX], ®s[CR_EBX],
|
|
®s[CR_ECX], ®s[CR_EDX]);
|
|
|
|
if (regs[cb->reg] & (1 << cb->bit))
|
|
set_cpu_cap(c, cb->feature);
|
|
}
|
|
}
|
|
|
|
/* leaf 0xb SMT level */
|
|
#define SMT_LEVEL 0
|
|
|
|
/* leaf 0xb sub-leaf types */
|
|
#define INVALID_TYPE 0
|
|
#define SMT_TYPE 1
|
|
#define CORE_TYPE 2
|
|
|
|
#define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff)
|
|
#define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f)
|
|
#define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff)
|
|
|
|
/*
|
|
* Check for extended topology enumeration cpuid leaf 0xb and if it
|
|
* exists, use it for populating initial_apicid and cpu topology
|
|
* detection.
|
|
*/
|
|
void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
unsigned int eax, ebx, ecx, edx, sub_index;
|
|
unsigned int ht_mask_width, core_plus_mask_width;
|
|
unsigned int core_select_mask, core_level_siblings;
|
|
static bool printed;
|
|
|
|
if (c->cpuid_level < 0xb)
|
|
return;
|
|
|
|
cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
|
|
|
|
/*
|
|
* check if the cpuid leaf 0xb is actually implemented.
|
|
*/
|
|
if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
|
|
return;
|
|
|
|
set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
|
|
|
|
/*
|
|
* initial apic id, which also represents 32-bit extended x2apic id.
|
|
*/
|
|
c->initial_apicid = edx;
|
|
|
|
/*
|
|
* Populate HT related information from sub-leaf level 0.
|
|
*/
|
|
core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
|
core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
|
|
|
sub_index = 1;
|
|
do {
|
|
cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
|
|
|
|
/*
|
|
* Check for the Core type in the implemented sub leaves.
|
|
*/
|
|
if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
|
|
core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
|
core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
|
break;
|
|
}
|
|
|
|
sub_index++;
|
|
} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
|
|
|
|
core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
|
|
|
|
c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
|
|
& core_select_mask;
|
|
c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
|
|
/*
|
|
* Reinit the apicid, now that we have extended initial_apicid.
|
|
*/
|
|
c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
|
|
|
|
c->x86_max_cores = (core_level_siblings / smp_num_siblings);
|
|
|
|
if (!printed) {
|
|
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
|
|
c->phys_proc_id);
|
|
if (c->x86_max_cores > 1)
|
|
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
|
|
c->cpu_core_id);
|
|
printed = 1;
|
|
}
|
|
return;
|
|
#endif
|
|
}
|