2008-03-19 20:14:52

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 0/79] smpboot integration

Hi,

This is a complement to my last patch series. In this one, I integrate smpboot.c
The end result is that i386 also uses the new hotplug state machine, and boot cpus
via cpu_up, instead of booting them in the preparation step, and only activating later.

The final diffstat says:
59 files changed, 1974 insertions(+), 2752 deletions(-)

Leftovers:

smp.h could also be easily integrated. But this series was too big already
setup64.c could also be completely moved to setup.c

Testing and bisectability:

The end result was tested in all my hardware (which includes qemu ;-).
It does not mean it will boot _your_ hardware, but I did my best ;-)

The tree at least compiles in more than 20 randconfigs (for each of x86_64 and i386)
For i386, each of the subarchitectures was compiled at least once. (By compile, I obviously
mean, every patch, individually)

Full diffstat:

a/arch/x86/kernel/smpboot_32.c | 68 -
a/arch/x86/kernel/smpboot_64.c | 73 -
a/include/asm-x86/nmi_64.h | 89 -
arch/x86/kernel/Makefile | 4
arch/x86/kernel/apic_32.c | 81 -
arch/x86/kernel/mpparse_32.c | 19
arch/x86/kernel/mpparse_64.c | 12
arch/x86/kernel/nmi_32.c | 2
arch/x86/kernel/smpboot.c | 1071 ++++++++++++++++
arch/x86/kernel/smpboot_32.c | 1617 ++++---------------------
arch/x86/kernel/smpboot_64.c | 949 +-------------
b/arch/x86/Kconfig | 2
b/arch/x86/Makefile | 2
b/arch/x86/kernel/Makefile | 2
b/arch/x86/kernel/acpi/boot.c | 2
b/arch/x86/kernel/apic_32.c | 23
b/arch/x86/kernel/apic_64.c | 13
b/arch/x86/kernel/bugs_64.c | 3
b/arch/x86/kernel/mpparse_32.c | 12
b/arch/x86/kernel/mpparse_64.c | 2
b/arch/x86/kernel/nmi_32.c | 2
b/arch/x86/kernel/nmi_64.c | 2
b/arch/x86/kernel/process_32.c | 10
b/arch/x86/kernel/setup.c | 103 +
b/arch/x86/kernel/setup64.c | 77 -
b/arch/x86/kernel/setup_32.c | 25
b/arch/x86/kernel/setup_64.c | 15
b/arch/x86/kernel/smpboot.c | 77 +
b/arch/x86/kernel/smpboot_32.c | 5
b/arch/x86/kernel/smpboot_64.c | 19
b/arch/x86/kernel/traps_64.c | 2
b/arch/x86/mach-voyager/voyager_smp.c | 7
b/arch/x86/mm/k8topology_64.c | 7
b/arch/x86/pci/numa.c | 8
b/arch/x86/vdso/Makefile | 2
b/include/asm-x86/apic.h | 3
b/include/asm-x86/apicdef.h | 7
b/include/asm-x86/mach-bigsmp/mach_apic.h | 7
b/include/asm-x86/mach-default/mach_apic.h | 11
b/include/asm-x86/mach-default/mach_apicdef.h | 5
b/include/asm-x86/mach-default/smpboot_hooks.h | 3
b/include/asm-x86/mach-es7000/mach_apic.h | 8
b/include/asm-x86/mach-summit/mach_apic.h | 4
b/include/asm-x86/mach-visws/smpboot_hooks.h | 5
b/include/asm-x86/mmzone_32.h | 3
b/include/asm-x86/nmi.h | 92 +
b/include/asm-x86/nmi_64.h | 3
b/include/asm-x86/smp.h | 3
b/include/asm-x86/smp_32.h | 5
b/include/asm-x86/smp_64.h | 12
b/include/asm-x86/topology.h | 9
include/asm-x86/apic.h | 2
include/asm-x86/apicdef.h | 6
include/asm-x86/mach-default/smpboot_hooks.h | 5
include/asm-x86/nmi.h | 5
include/asm-x86/nmi_32.h | 61
include/asm-x86/smp.h | 29
include/asm-x86/smp_32.h | 16
include/asm-x86/smp_64.h | 15
59 files changed, 1974 insertions(+), 2752 deletions(-)


2008-03-19 19:41:10

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 14/79] [PATCH] move state update out of ipi_lock

From: Glauber Costa <[email protected]>

it does not need to be inside lock. Do the way i386 does.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index c213345..cfcfd2c 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -233,10 +233,10 @@ void __cpuinit start_secondary(void)
*/
spin_unlock(&vector_lock);
cpu_set(smp_processor_id(), cpu_online_map);
- per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
-
unlock_ipi_call_lock();

+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+
setup_secondary_clock();

cpu_idle();
--
1.5.0.6

2008-03-19 19:41:36

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 07/79] [PATCH] provide specialized identification routines for x86_64

From: Glauber Costa <[email protected]>

provide two specialized identify_secondary_cpu() and identify_boot_cpu()
routines for x86_64. Although not strictly needed, they are functionally
correct, and will ease integration with i386

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/setup_64.c | 14 ++++++++++++--
1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 089ce10..352aa23 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -1051,14 +1051,24 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
#endif
select_idle_routine(c);

- if (c != &boot_cpu_data)
- mtrr_ap_init();
#ifdef CONFIG_NUMA
numa_add_cpu(smp_processor_id());
#endif

}

+void __cpuinit identify_boot_cpu(void)
+{
+ identify_cpu(&boot_cpu_data);
+}
+
+void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
+{
+ BUG_ON(c == &boot_cpu_data);
+ identify_cpu(c);
+ mtrr_ap_init();
+}
+
static __init int setup_noclflush(char *arg)
{
setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
--
1.5.0.6

2008-03-19 19:40:49

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 12/79] [PATCH] don't call local_irq_enable before entering idle

From: Glauber Costa <[email protected]>

the call to idle is guaranteed to do it.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 0bfb31e..6c16165 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -214,9 +214,6 @@ static void __cpuinit start_secondary(void *unused)
unlock_ipi_call_lock();
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;

- /* We can take interrupts now: we're officially "up". */
- local_irq_enable();
-
wmb();
cpu_idle();
}
--
1.5.0.6

2008-03-19 19:39:54

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 08/79] [PATCH] use identify_boot_cpu

From: Glauber Costa <[email protected]>

Call this function instead of identify_cpu in bugs_64.c

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/bugs_64.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/bugs_64.c b/arch/x86/kernel/bugs_64.c
index 8f520f9..60207e9 100644
--- a/arch/x86/kernel/bugs_64.c
+++ b/arch/x86/kernel/bugs_64.c
@@ -12,7 +12,7 @@

void __init check_bugs(void)
{
- identify_cpu(&boot_cpu_data);
+ identify_boot_cpu();
#if !defined(CONFIG_SMP)
printk("CPU: ");
print_cpu_info(&boot_cpu_data);
--
1.5.0.6

2008-03-19 19:40:20

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 09/79] [PATCH] call identify_secondary_cpu in smp_store_cpu_info

From: Glauber Costa <[email protected]>

Call it conditionally for secondary cpus. This behaviour
matches i386

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 1da28c6..f84e30d 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -96,7 +96,8 @@ static void __cpuinit smp_store_cpu_info(int id)

*c = boot_cpu_data;
c->cpu_index = id;
- identify_cpu(c);
+ if (id != 0)
+ identify_secondary_cpu(c);
}

static inline void wait_for_init_deassert(atomic_t *deassert)
--
1.5.0.6

2008-03-19 19:44:46

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 06/79] [PATCH] decouple call to print_cpu_info from smp_store_cpu_info

From: Glauber Costa <[email protected]>

This will ease integration with i386

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 13ab112..1da28c6 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -97,7 +97,6 @@ static void __cpuinit smp_store_cpu_info(int id)
*c = boot_cpu_data;
c->cpu_index = id;
identify_cpu(c);
- print_cpu_info(c);
}

static inline void wait_for_init_deassert(atomic_t *deassert)
@@ -568,6 +567,8 @@ do_rest:
if (cpu_isset(cpu, cpu_callin_map)) {
/* number CPUs logically, starting from 1 (BSP is 0) */
Dprintk("CPU has booted.\n");
+ printk(KERN_INFO "CPU%d: ", cpu);
+ print_cpu_info(&cpu_data(cpu));
} else {
boot_error = 1;
if (*((volatile unsigned char *)phys_to_virt(SMP_TRAMPOLINE_BASE))
@@ -751,6 +752,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
*/

setup_boot_clock();
+ printk(KERN_INFO "CPU%d: ", 0);
+ print_cpu_info(&cpu_data(0));
}

/*
--
1.5.0.6

2008-03-19 19:44:25

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 02/79] [PATCH] add loglevel to printks

Add loglevel facilities to printks in __inquire_remote_apic.
the levels are the ones to match x86_64 ones.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 11 ++++++-----
1 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index bea2d32..8676eec 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -373,17 +373,18 @@ static inline void __inquire_remote_apic(int apicid)
int timeout;
u32 status;

- printk("Inquiring remote APIC #%d...\n", apicid);
+ printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);

for (i = 0; i < ARRAY_SIZE(regs); i++) {
- printk("... APIC #%d %s: ", apicid, names[i]);
+ printk(KERN_INFO "... APIC #%d %s: ", apicid, names[i]);

/*
* Wait for idle.
*/
status = safe_apic_wait_icr_idle();
if (status)
- printk("a previous APIC delivery may have failed\n");
+ printk(KERN_CONT
+ "a previous APIC delivery may have failed\n");

apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
@@ -397,10 +398,10 @@ static inline void __inquire_remote_apic(int apicid)
switch (status) {
case APIC_ICR_RR_VALID:
status = apic_read(APIC_RRR);
- printk("%lx\n", status);
+ printk(KERN_CONT "%08x\n", status);
break;
default:
- printk("failed\n");
+ printk(KERN_CONT "failed\n");
}
}
}
--
1.5.0.6

2008-03-19 19:46:16

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 15/79] [PATCH] provide APIC_INTEGRATED definition for x86_64

From: Glauber Costa <[email protected]>

it is always integrated, so define as 1.

Signed-off-by: Glauber Costa <[email protected]>
---
include/asm-x86/apicdef.h | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/include/asm-x86/apicdef.h b/include/asm-x86/apicdef.h
index 550af7a..b0c6b28 100644
--- a/include/asm-x86/apicdef.h
+++ b/include/asm-x86/apicdef.h
@@ -22,7 +22,11 @@
#define APIC_LVR_MASK 0xFF00FF
#define GET_APIC_VERSION(x) ((x)&0xFFu)
#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFFu)
-#define APIC_INTEGRATED(x) ((x)&0xF0u)
+#ifdef CONFIG_X86_32
+# define APIC_INTEGRATED(x) ((x)&0xF0u)
+#else
+# define APIC_INTEGRATED(x) (1)
+#endif
#define APIC_XAPIC(x) ((x) >= 0x14)
#define APIC_TASKPRI 0x80
#define APIC_TPRI_MASK 0xFFu
--
1.5.0.6

2008-03-19 19:54:47

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration


* Ingo Molnar <[email protected]> wrote:

> the small fix below was needed - it is possible to build ACPI on
> 32-bit with APIC support disabled. Otherwise it's looking good in my
> testing.

another fix for a small (and rare) build bug i found is below: it is
possible to build a kernel with CONFIG_X86_MPPARSE but without
CONFIG_SMP. In that case x86_bios_cpu_apicid has to be provided, and the
use of the early-apicids has to be inhibited.

Ingo

---
arch/x86/kernel/mpparse_32.c | 6 ++++++
1 file changed, 6 insertions(+)

Index: linux/arch/x86/kernel/mpparse_32.c
===================================================================
--- linux.orig/arch/x86/kernel/mpparse_32.c
+++ linux/arch/x86/kernel/mpparse_32.c
@@ -76,6 +76,10 @@ unsigned disabled_cpus __cpuinitdata;
/* Bitmask of physically existing CPUs */
physid_mask_t phys_cpu_present_map;

+#ifndef CONFIG_SMP
+DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
+#endif
+
/*
* Intel MP BIOS table parsing routines:
*/
@@ -230,6 +234,7 @@ static void __cpuinit MP_processor_info
def_to_bigsmp = 1;
}
}
+#ifdef CONFIG_SMP
/* are we being called early in kernel startup? */
if (x86_cpu_to_apicid_early_ptr) {
u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr;
@@ -241,6 +246,7 @@ static void __cpuinit MP_processor_info
per_cpu(x86_cpu_to_apicid, cpu) = m->mpc_apicid;
per_cpu(x86_bios_cpu_apicid, cpu) = m->mpc_apicid;
}
+#endif
cpu_set(cpu, cpu_present_map);
}

2008-03-19 19:56:05

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 01/79] [PATCH] change var types in __inquire_remote_apic

change some variables' types in __inquire_remote_apic to
match x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 2dd95ba..bea2d32 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -368,10 +368,10 @@ static void unmap_cpu_to_logical_apicid(int cpu)

static inline void __inquire_remote_apic(int apicid)
{
- int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
+ unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
char *names[] = { "ID", "VERSION", "SPIV" };
int timeout;
- unsigned long status;
+ u32 status;

printk("Inquiring remote APIC #%d...\n", apicid);

--
1.5.0.6

2008-03-19 19:56:22

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 13/79] [PATCH] move setup_secondary_clock a little bit down in the function

From: Glauber Costa <[email protected]>

This is done so we call setup_secondary_clock() in the same place x86_64
does. A separate patch for this is appearantly not needed. But clock
initialization is such a delicate thing, that it's safer to do this way

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 6c16165..4e5416e 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -185,7 +185,6 @@ static void __cpuinit start_secondary(void *unused)
*/
check_tsc_sync_target();

- setup_secondary_clock();
if (nmi_watchdog == NMI_IO_APIC) {
disable_8259A_irq(0);
enable_NMI_through_LVT0();
@@ -214,6 +213,8 @@ static void __cpuinit start_secondary(void *unused)
unlock_ipi_call_lock();
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;

+ setup_secondary_clock();
+
wmb();
cpu_idle();
}
--
1.5.0.6

2008-03-19 19:56:43

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 05/79] [PATCH] add an smp_apply_quirks to smpboot_32.c

From: Glauber Costa <[email protected]>

The split of smp_store_cpu_info in a quirks-only part
will ease integration with x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 30 ++++++++++++++++++------------
1 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 8676eec..e050064 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -78,19 +78,8 @@ static void map_cpu_to_logical_apicid(void);
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

-/*
- * The bootstrap kernel entry code has set these up. Save them for
- * a given CPU
- */
-
-void __cpuinit smp_store_cpu_info(int id)
+static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
{
- struct cpuinfo_x86 *c = &cpu_data(id);
-
- *c = boot_cpu_data;
- c->cpu_index = id;
- if (id!=0)
- identify_secondary_cpu(c);
/*
* Mask B, Pentium, but not Pentium MMX
*/
@@ -138,6 +127,23 @@ void __cpuinit smp_store_cpu_info(int id)

valid_k7:
;
+
+}
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+
+void __cpuinit smp_store_cpu_info(int id)
+{
+ struct cpuinfo_x86 *c = &cpu_data(id);
+
+ *c = boot_cpu_data;
+ c->cpu_index = id;
+ if (id != 0)
+ identify_secondary_cpu(c);
+ smp_apply_quirks(c);
}

static atomic_t init_deasserted;
--
1.5.0.6

2008-03-19 19:58:16

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 04/79] [PATCH] use start_ipi_hook in x86_64

From: Glauber Costa <[email protected]>

It is used to match i386. The definition for the non-paravirt
case is moved to smp.h instead of smp_32.h

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 8 ++++++++
include/asm-x86/smp.h | 3 +++
include/asm-x86/smp_32.h | 4 ----
3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 57ebe6c..13ab112 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -345,6 +345,14 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
num_starts = 2;

/*
+ * Paravirt / VMI wants a startup IPI hook here to set up the
+ * target processor state.
+ */
+ startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
+ (unsigned long) init_rsp);
+
+
+ /*
* Run STARTUP IPI loop.
*/
Dprintk("#startup loops: %d.\n", num_starts);
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 513c857..4dc271b 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -33,6 +33,9 @@ struct smp_ops {
extern void set_cpu_sibling_map(int cpu);

#ifdef CONFIG_SMP
+#ifndef CONFIG_PARAVIRT
+#define startup_ipi_hook(phys_apicid, start_eip, start_esp) do { } while (0)
+#endif
extern struct smp_ops smp_ops;

static inline void smp_send_stop(void)
diff --git a/include/asm-x86/smp_32.h b/include/asm-x86/smp_32.h
index 4fec2fe..76740de 100644
--- a/include/asm-x86/smp_32.h
+++ b/include/asm-x86/smp_32.h
@@ -30,10 +30,6 @@ DECLARE_PER_CPU(u16, cpu_llc_id);
DECLARE_PER_CPU(u16, x86_cpu_to_apicid);

#ifdef CONFIG_SMP
-#ifndef CONFIG_PARAVIRT
-#define startup_ipi_hook(phys_apicid, start_eip, start_esp) do { } while (0)
-#endif
-
/*
* This function is needed by all SMP systems. It must _always_ be valid
* from the initial startup. We map APIC_BASE very early in page_setup(),
--
1.5.0.6

2008-03-19 19:58:49

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 26/79] [PATCH] make node to apic mapping declarations unconditional

From: Glauber Costa <[email protected]>

Instead of declaring them inside of X86_64 ifdef, do it
unconditionally

Signed-off-by: Glauber Costa <[email protected]>
---
include/asm-x86/topology.h | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/asm-x86/topology.h b/include/asm-x86/topology.h
index fd38c3a..5bc825b 100644
--- a/include/asm-x86/topology.h
+++ b/include/asm-x86/topology.h
@@ -33,15 +33,15 @@ struct pci_bus;
/* Mappings between logical cpu number and node number */
#ifdef CONFIG_X86_32
extern int cpu_to_node_map[];
-
#else
-DECLARE_PER_CPU(int, x86_cpu_to_node_map);
-extern int x86_cpu_to_node_map_init[];
-extern void *x86_cpu_to_node_map_early_ptr;
/* Returns the number of the current Node. */
#define numa_node_id() (early_cpu_to_node(raw_smp_processor_id()))
#endif

+DECLARE_PER_CPU(int, x86_cpu_to_node_map);
+extern int x86_cpu_to_node_map_init[];
+extern void *x86_cpu_to_node_map_early_ptr;
+
extern cpumask_t node_to_cpumask_map[];

#define NUMA_NO_NODE (-1)
--
1.5.0.6

2008-03-19 19:59:11

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 20/79] [PATCH] do tests before do_boot_cpu in i386

From: Glauber Costa <[email protected]>

Do tests before do_boot_cpu in native_cpu_up for i386.
Tests are a little bit broader than originally, and are the
same as x86_64. Test for smp_callin is not applicable right now
and is deferred.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 18 +++++++++++++-----
1 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 8144aa3..147af81 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -711,10 +711,6 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
int apicid, ret;

apicid = per_cpu(x86_cpu_to_apicid, cpu);
- if (apicid == BAD_APICID) {
- ret = -ENODEV;
- goto exit;
- }

info.complete = &done;
info.apicid = apicid;
@@ -952,10 +948,22 @@ void __init native_smp_prepare_boot_cpu(void)

int __cpuinit native_cpu_up(unsigned int cpu)
{
+ int apicid = cpu_present_to_apicid(cpu);
unsigned long flags;
-#ifdef CONFIG_HOTPLUG_CPU
int ret = 0;

+ WARN_ON(irqs_disabled());
+
+ Dprintk("++++++++++++++++++++=_---CPU UP %u\n", cpu);
+
+ if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
+ !physid_isset(apicid, phys_cpu_present_map)) {
+ printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_HOTPLUG_CPU
+
/*
* We do warm boot only on cpus that had booted earlier
* Otherwise cold boot is all handled from smp_boot_cpus().
--
1.5.0.6

2008-03-19 19:59:39

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 35/79] [PATCH] add subarch support (for headers) to x86_64

From: Glauber Costa <[email protected]>

this patch allows x86_64 to use subarch mach_ headers
in practice, since x86_64 does not have any subarch, it
will use mach_default. But it will allow for substantially
less code duplication

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/Makefile | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 03131ce..3cff3c8 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -151,7 +151,6 @@ mflags-y += -Iinclude/asm-x86/mach-default
# 64 bit does not support subarch support - clear sub arch variables
fcore-$(CONFIG_X86_64) :=
mcore-$(CONFIG_X86_64) :=
-mflags-$(CONFIG_X86_64) :=

KBUILD_CFLAGS += $(mflags-y)
KBUILD_AFLAGS += $(mflags-y)
--
1.5.0.6

2008-03-19 20:00:07

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 39/79] [PATCH] don't set maps in native_smp_prepare_boot_cpu()

From: Glauber Costa <[email protected]>

By this time, they are already set in init routines

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 87c9a75..bfdfe3c 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -889,10 +889,7 @@ void __init native_smp_prepare_boot_cpu(void)
init_gdt(cpu);
switch_to_new_gdt();

- cpu_set(cpu, cpu_online_map);
cpu_set(cpu, cpu_callout_map);
- cpu_set(cpu, cpu_present_map);
- cpu_set(cpu, cpu_possible_map);
__get_cpu_var(cpu_state) = CPU_ONLINE;
}

--
1.5.0.6

2008-03-19 20:00:46

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 71/79] [PATCH] assign nr_ioapics = 0 in smpboot_hooks.h

From: Glauber Costa <[email protected]>

change smpboot_setup_io_apic() by to match x86_64 behaviour

Signed-off-by: Glauber Costa <[email protected]>
---
include/asm-x86/mach-default/smpboot_hooks.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/asm-x86/mach-default/smpboot_hooks.h b/include/asm-x86/mach-default/smpboot_hooks.h
index 7f45f63..8e1c6c0 100644
--- a/include/asm-x86/mach-default/smpboot_hooks.h
+++ b/include/asm-x86/mach-default/smpboot_hooks.h
@@ -41,4 +41,6 @@ static inline void smpboot_setup_io_apic(void)
*/
if (!skip_ioapic_setup && nr_ioapics)
setup_IO_APIC();
+ else
+ nr_ioapics = 0;
}
--
1.5.0.6

2008-03-19 20:01:18

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 29/79] [PATCH] fill bios cpu to apicid maps

From: Glauber Costa <[email protected]>

We fill the per-cpu (or array) that maps
bios cpu id to apicid in mpparse_32.c, the way x86_64 does

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/mpparse_32.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/mpparse_32.c b/arch/x86/kernel/mpparse_32.c
index c6a9789..56fb828 100644
--- a/arch/x86/kernel/mpparse_32.c
+++ b/arch/x86/kernel/mpparse_32.c
@@ -76,8 +76,6 @@ unsigned disabled_cpus __cpuinitdata;
/* Bitmask of physically existing CPUs */
physid_mask_t phys_cpu_present_map;

-u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
-
/*
* Intel MP BIOS table parsing routines:
*/
@@ -221,7 +219,14 @@ static void __cpuinit MP_processor_info (struct mpc_config_processor *m)
def_to_bigsmp = 1;
}
}
- bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
+ /* are we being called early in kernel startup? */
+ if (x86_cpu_to_apicid_early_ptr) {
+ u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr;
+ bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
+ } else {
+ int cpu = num_processors - 1;
+ per_cpu(x86_bios_cpu_apicid, cpu) = m->mpc_apicid;
+ }
}

static void __init MP_bus_info (struct mpc_config_bus *m)
--
1.5.0.6

2008-03-19 20:01:38

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 45/79] [PATCH] fix apic acking of irqs

From: Glauber Costa <[email protected]>

EOI is a write-only register. Using write around will have the effect
of reading it, which will make all subsequent reads of the ESR register
to return an error code. It was unnotices for quite a while because main sources
of reading the ESR register where done prior to apic interrupt enabling.

Signed-off-by: Glauber Costa <[email protected]>
---
include/asm-x86/apic.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h
index db5f750..0d6ea74 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -103,7 +103,7 @@ static inline void ack_APIC_irq(void)
*/

/* Docs say use 0 for future compatibility */
- apic_write_around(APIC_EOI, 0);
+ apic_write(APIC_EOI, 0);
}

extern int lapic_get_maxlvt(void);
--
1.5.0.6

2008-03-19 20:01:59

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 25/79] [PATCH] initialize map pointers in setup_32.c

From: Glauber Costa <[email protected]>

this will serve as a reference as to whether or not to
use the per_cpu variables in mpparse. Done the same way
as x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/setup_32.c | 24 ++++++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index db9d585..599ce01 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -724,6 +724,18 @@ char * __init __attribute__((weak)) memory_setup(void)
return machine_specific_memory_setup();
}

+#ifdef CONFIG_NUMA
+/*
+ * In the golden day, when everything among i386 and x86_64 will be
+ * integrated, this will not live here
+ */
+void *x86_cpu_to_node_map_early_ptr;
+int x86_cpu_to_node_map_init[NR_CPUS] = {
+ [0 ... NR_CPUS-1] = NUMA_NO_NODE
+};
+DEFINE_PER_CPU(int, x86_cpu_to_node_map) = NUMA_NO_NODE;
+#endif
+
/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
@@ -856,6 +868,18 @@ void __init setup_arch(char **cmdline_p)

io_delay_init();

+#ifdef CONFIG_X86_SMP
+ /*
+ * setup to use the early static init tables during kernel startup
+ * X86_SMP will exclude sub-arches that don't deal well with it.
+ */
+ x86_cpu_to_apicid_early_ptr = (void *)x86_cpu_to_apicid_init;
+ x86_bios_cpu_apicid_early_ptr = (void *)x86_bios_cpu_apicid_init;
+#ifdef CONFIG_NUMA
+ x86_cpu_to_node_map_early_ptr = (void *)x86_cpu_to_node_map_init;
+#endif
+#endif
+
#ifdef CONFIG_X86_GENERICARCH
generic_apic_probe();
#endif
--
1.5.0.6

2008-03-19 20:02:25

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 73/79] [PATCH] add extra sanity check

From: Glauber Costa <[email protected]>

This test exists in x86_64 and also applies to i386. So we add it

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 6be36d3..ae23b60 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -118,6 +118,12 @@ static void __init disable_smp(void)

static int __init smp_sanity_check(unsigned max_cpus)
{
+ if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
+ printk(KERN_WARNING "weird, boot CPU (#%d) not listed"
+ "by the BIOS.\n", hard_smp_processor_id());
+ physid_set(hard_smp_processor_id(), phys_cpu_present_map);
+ }
+
/*
* If we couldn't find an SMP configuration at boot time,
* get out of here now!
--
1.5.0.6

2008-03-19 19:56:57

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 22/79] [PATCH] move assignment of CPU_PREPARE before do_boot_cpu

From: Glauber Costa <[email protected]>

Done to match x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index ee6f3bd..0e86ccc 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -958,6 +958,7 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return -EINVAL;
}

+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
#ifdef CONFIG_HOTPLUG_CPU

/*
@@ -976,7 +977,6 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return -EIO;
}

- per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
/* Unleash the CPU! */
cpu_set(cpu, smp_commenced_mask);

--
1.5.0.6

2008-03-19 20:03:11

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 44/79] [PATCH] don't initialize sibling and core maps during preparation

From: Glauber Costa <[email protected]>

it is redundant, since it is already done by set_cpu_sibling_map()

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 12 ------------
1 files changed, 0 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index a350553..5cae17f 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -855,18 +855,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
++kicked;
}

- /*
- * construct cpu_sibling_map, so that we can tell sibling CPUs
- * efficiently.
- */
- for_each_possible_cpu(cpu) {
- cpus_clear(per_cpu(cpu_sibling_map, cpu));
- cpus_clear(per_cpu(cpu_core_map, cpu));
- }
-
- cpu_set(0, per_cpu(cpu_sibling_map, 0));
- cpu_set(0, per_cpu(cpu_core_map, 0));
-
smpboot_setup_io_apic();

setup_boot_clock();
--
1.5.0.6

2008-03-19 19:57:33

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 27/79] [PATCH] fix alloc_bootmem_pages_node macro

From: Glauber Costa <[email protected]>

missing a semicolon

Signed-off-by: Glauber Costa <[email protected]>
---
include/asm-x86/mmzone_32.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/asm-x86/mmzone_32.h b/include/asm-x86/mmzone_32.h
index 274a595..b9f5be2 100644
--- a/include/asm-x86/mmzone_32.h
+++ b/include/asm-x86/mmzone_32.h
@@ -129,7 +129,7 @@ static inline int pfn_valid(int pfn)
struct pglist_data __maybe_unused \
*__alloc_bootmem_node__pgdat = (pgdat); \
__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, \
- __pa(MAX_DMA_ADDRESS)) \
+ __pa(MAX_DMA_ADDRESS)); \
})
#define alloc_bootmem_low_pages_node(pgdat, x) \
({ \
--
1.5.0.6

2008-03-19 19:57:53

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 16/79] [PATCH] use APIC_INTEGRATED tests in x86_64

From: Glauber Costa <[email protected]>

This patch does not change the behaviour of x86_64, since APIC_INTEGRATED
is always defined as (1). But the code now matches exactly i386 version
(well, this part of the code, at least)

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 14 +++++++++++++-
1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index cfcfd2c..d7b59d6 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -295,6 +295,15 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
unsigned long send_status, accept_status = 0;
int maxlvt, num_starts, j;

+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+ if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ }
+
Dprintk("Asserting INIT.\n");

/*
@@ -327,7 +336,10 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
mb();
atomic_set(&init_deasserted, 1);

- num_starts = 2;
+ if (APIC_INTEGRATED(apic_version[phys_apicid]))
+ num_starts = 2;
+ else
+ num_starts = 0;

/*
* Paravirt / VMI wants a startup IPI hook here to set up the
--
1.5.0.6

2008-03-19 20:02:45

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 17/79] [PATCH] add barriers statement

goal is to have i386 and x86_64 closer, so we
add barriers to match

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 4 ++++
arch/x86/kernel/smpboot_64.c | 1 +
2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 4e5416e..a232f4d 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -180,6 +180,9 @@ static void __cpuinit start_secondary(void *unused)
smp_callin();
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
cpu_relax();
+
+ /* otherwise gcc will move up smp_processor_id before the cpu_init */
+ barrier();
/*
* Check TSC synchronization with the BP:
*/
@@ -432,6 +435,7 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
Dprintk("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle();

+ mb();
atomic_set(&init_deasserted, 1);

/*
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index d7b59d6..a9cc911 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -239,6 +239,7 @@ void __cpuinit start_secondary(void)

setup_secondary_clock();

+ wmb();
cpu_idle();
}

--
1.5.0.6

2008-03-19 20:04:34

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 68/79] [PATCH] use physical id when disabling smp

From: Glauber Costa <[email protected]>

if smp configuration is not found at all, hook into 0.
This is done to match x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 75fb506..14db038 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -106,7 +106,11 @@ static void __init disable_smp(void)
cpu_possible_map = cpumask_of_cpu(0);
cpu_present_map = cpumask_of_cpu(0);
smpboot_clear_io_apic_irqs();
- phys_cpu_present_map = physid_mask_of_physid(0);
+ if (smp_found_config)
+ phys_cpu_present_map =
+ physid_mask_of_physid(boot_cpu_physical_apicid);
+ else
+ phys_cpu_present_map = physid_mask_of_physid(0);
map_cpu_to_logical_apicid();
cpu_set(0, per_cpu(cpu_sibling_map, 0));
cpu_set(0, per_cpu(cpu_core_map, 0));
--
1.5.0.6

2008-03-19 20:05:47

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 55/79] [PATCH] calibrate delay with irqs enabled

From: Glauber Costa <[email protected]>

We do it to make it close to x86_64. The later needs it,
otherwise the nmi watchdog can get into the scene and kill us
with a hammer.

Enabling irqs here used to trigger a bug in i386. This is because
time irq handling relies upon structures that are only initialized
after smp initcalls (More precisely, it will find
per_cpu(hrtimer_bases, cpu)->cb_pending list not initialized and crash)

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index dbfaeb3..bd2f886 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -167,7 +167,9 @@ static void __cpuinit smp_callin(void)
/*
* Get our bogomips.
*/
+ local_irq_enable();
calibrate_delay();
+ local_irq_disable();
Dprintk("Stack at about %p\n",&cpuid);

/*
--
1.5.0.6

2008-03-19 20:06:15

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 36/79] [PATCH] include mach_wakecpu.h in smpboot_64

From: Glauber Costa <[email protected]>

Do it and also fix conflicts, which automatically makes
x86_64 look closer to i386

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 11 +++--------
1 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index c3e770b..c6c993f 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -60,6 +60,8 @@
#include <asm/hw_irq.h>
#include <asm/numa.h>

+#include <mach_wakecpu.h>
+
/* Set when the idlers are all forked */
int smp_threads_ready;

@@ -85,13 +87,6 @@ struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p))
#endif

-static inline void wait_for_init_deassert(atomic_t *deassert)
-{
- while (!atomic_read(deassert))
- cpu_relax();
- return;
-}
-
static atomic_t init_deasserted __cpuinitdata;

/*
@@ -247,7 +242,7 @@ extern volatile unsigned long init_rsp;
extern void (*initial_code)(void);

#ifdef APIC_DEBUG
-static void inquire_remote_apic(int apicid)
+static void __inquire_remote_apic(int apicid)
{
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
char *names[] = { "ID", "VERSION", "SPIV" };
--
1.5.0.6

2008-03-19 20:06:32

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 42/79] [PATCH] call check_nmi_watchdog explicitly in native_smp_cpus_done

From: Glauber Costa <[email protected]>

With this, remove its late_initcall marker from nmi_32.c

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/nmi_32.c | 2 --
arch/x86/kernel/smpboot_32.c | 1 +
2 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c
index daea273..9f9eb5b 100644
--- a/arch/x86/kernel/nmi_32.c
+++ b/arch/x86/kernel/nmi_32.c
@@ -129,8 +129,6 @@ int __init check_nmi_watchdog(void)
kfree(prev_nmi_count);
return 0;
}
-/* This needs to happen later in boot so counters are working */
-late_initcall(check_nmi_watchdog);

static int __init setup_nmi_watchdog(char *str)
{
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index bfdfe3c..1f3aff4 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -963,5 +963,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
#endif
+ check_nmi_watchdog();
zap_low_mappings();
}
--
1.5.0.6

2008-03-19 20:06:48

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 03/79] [PATCH] use apic_*_around instead of apic_write in x86_64

This patch replaces apic_read() for apic_read_around()
and apic_write for apic_write_around() in smpboot_64.c
We do it to have a common usage between x86_64 and i386.
In the former, it will always simply expand to apic_write

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 4f6d976..57ebe6c 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -281,8 +281,8 @@ static void inquire_remote_apic(int apicid)
printk(KERN_CONT
"a previous APIC delivery may have failed\n");

- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+ apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);

timeout = 0;
do {
@@ -315,12 +315,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
/*
* Turn INIT on target chip
*/
- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));

/*
* Send IPI
*/
- apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
| APIC_DM_INIT);

Dprintk("Waiting for send to finish...\n");
@@ -331,10 +331,10 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
Dprintk("Deasserting INIT.\n");

/* Target chip */
- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));

/* Send IPI */
- apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);

Dprintk("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle();
@@ -353,6 +353,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta

for (j = 1; j <= num_starts; j++) {
Dprintk("Sending STARTUP #%d.\n",j);
+ apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
Dprintk("After apic_write.\n");
@@ -362,11 +363,11 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
*/

/* Target chip */
- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));

/* Boot on the stack */
/* Kick the second */
- apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12));
+ apic_write_around(APIC_ICR, APIC_DM_STARTUP | (start_rip>>12));

/*
* Give the other CPU some time to accept the IPI.
@@ -386,6 +387,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
* Due to the Pentium erratum 3AP.
*/
if (maxlvt > 3) {
+ apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
}
accept_status = (apic_read(APIC_ESR) & 0xEF);
--
1.5.0.6

2008-03-19 20:08:16

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 40/79] [PATCH] wipe get_nmi_reason out of nmi_64.h

From: Glauber Costa <[email protected]>

use mach_traps when it is supposed to be used.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/nmi_64.c | 2 ++
arch/x86/kernel/traps_64.c | 2 ++
include/asm-x86/nmi_64.h | 2 --
3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c
index bd0fac5..5a29ded 100644
--- a/arch/x86/kernel/nmi_64.c
+++ b/arch/x86/kernel/nmi_64.c
@@ -26,6 +26,8 @@
#include <asm/proto.h>
#include <asm/mce.h>

+#include <mach_traps.h>
+
int unknown_nmi_panic;
int nmi_watchdog_enabled;
int panic_on_unrecovered_nmi;
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index 3d36144..6d883b1 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -33,6 +33,8 @@
#include <linux/kdebug.h>
#include <linux/utsname.h>

+#include <mach_traps.h>
+
#if defined(CONFIG_EDAC)
#include <linux/edac.h>
#endif
diff --git a/include/asm-x86/nmi_64.h b/include/asm-x86/nmi_64.h
index 2eeb74e..94a5b19 100644
--- a/include/asm-x86/nmi_64.h
+++ b/include/asm-x86/nmi_64.h
@@ -36,8 +36,6 @@ static inline void unset_nmi_pm_callback(struct pm_dev * dev)
extern void default_do_nmi(struct pt_regs *);
extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);

-#define get_nmi_reason() inb(0x61)
-
extern int unknown_nmi_panic;
extern int nmi_watchdog_enabled;

--
1.5.0.6

2008-03-19 20:08:50

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 60/79] [PATCH] add callin tests to cpu_up

From: Glauber Costa <[email protected]>

Now that we boot cpus here, callin_map has this meaning (same
as x86_64)

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 20 +++++++++++++-------
1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 4ba5ab2..33758a2 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -839,6 +839,7 @@ int __cpuinit native_cpu_up(unsigned int cpu)
{
int apicid = cpu_present_to_apicid(cpu);
unsigned long flags;
+ int err;

WARN_ON(irqs_disabled());

@@ -851,6 +852,14 @@ int __cpuinit native_cpu_up(unsigned int cpu)
}

/*
+ * Already booted CPU?
+ */
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ Dprintk("do_boot_cpu %d Already started\n", cpu);
+ return -ENOSYS;
+ }
+
+ /*
* Save current MTRR state in case it was changed since early boot
* (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
*/
@@ -863,15 +872,12 @@ int __cpuinit native_cpu_up(unsigned int cpu)
min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
flush_tlb_all();

- do_boot_cpu(apicid, cpu);
-
- /* In case one didn't come up */
- if (!cpu_isset(cpu, cpu_callin_map)) {
- printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu);
- return -EIO;
+ err = do_boot_cpu(apicid, cpu);
+ if (err < 0) {
+ Dprintk("do_boot_cpu failed %d\n", err);
+ return err;
}

-
/*
* Check TSC synchronization with the AP (keep irqs disabled
* while doing so):
--
1.5.0.6

2008-03-19 20:09:21

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 47/79] [PATCH] do not zap_low_mappings in __smp_prepare_cpus

From: Glauber Costa <[email protected]>

It was okay when cpus were cold booted before this point.
But with the new state machine, they will not have arrived to
the trampoline yet. zapping low mappings will have the bad effect
of breaking it completely after paging enablement

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 255c6f7..88ee655 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -195,11 +195,6 @@ static void __cpuinit start_secondary(void *unused)
enable_NMI_through_LVT0();
enable_8259A_irq(0);
}
- /*
- * low-memory mappings have been cleared, flush them from
- * the local TLBs too.
- */
- local_flush_tlb();

/* This must be done before setting cpu_online_map */
set_cpu_sibling_map(raw_smp_processor_id());
@@ -714,8 +709,6 @@ static void __cpuinit __smp_prepare_cpu(int cpu)
schedule_work(&info.task);
wait_for_completion(&done);
}
-
- zap_low_mappings();
}
#endif

--
1.5.0.6

2008-03-19 20:09:39

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 52/79] [PATCH] modify smp_callin in x86_64 to look like i386

From: Glauber Costa <[email protected]>

We introduce empty macros just to make them look like the same

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index b9384b3..e93fff4 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -90,6 +90,9 @@ struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;

static atomic_t init_deasserted __cpuinitdata;

+#define smp_callin_clear_local_apic() do {} while (0)
+#define map_cpu_to_logical_apicid() do {} while (0)
+
/*
* Report back to the Boot Processor.
* Running on AP.
@@ -152,8 +155,10 @@ void __cpuinit smp_callin(void)
*/

Dprintk("CALLIN, before setup_local_APIC().\n");
+ smp_callin_clear_local_apic();
setup_local_APIC();
end_local_APIC_setup();
+ map_cpu_to_logical_apicid();

/*
* Get our bogomips.
--
1.5.0.6

2008-03-19 20:10:04

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 51/79] [PATCH] don't span a new worker in __smp_prepare_cpu

From: Glauber Costa <[email protected]>

We can do it now that do_boot_cpu has its own worker.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 30 ++----------------------------
1 files changed, 2 insertions(+), 28 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index fc1eb52..c03596e 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -699,44 +699,18 @@ void cpu_exit_clear(void)
}
#endif

-struct warm_boot_cpu_info {
- struct completion *complete;
- struct work_struct task;
- int apicid;
- int cpu;
-};
-
-static void __cpuinit do_warm_boot_cpu(struct work_struct *work)
-{
- struct warm_boot_cpu_info *info =
- container_of(work, struct warm_boot_cpu_info, task);
- do_boot_cpu(info->apicid, info->cpu);
- complete(info->complete);
-}
-
static void __cpuinit __smp_prepare_cpu(int cpu)
{
- DECLARE_COMPLETION_ONSTACK(done);
- struct warm_boot_cpu_info info;
int apicid;

apicid = per_cpu(x86_cpu_to_apicid, cpu);

- info.complete = &done;
- info.apicid = apicid;
- info.cpu = cpu;
- INIT_WORK(&info.task, do_warm_boot_cpu);
-
/* init low mem mapping */
clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
flush_tlb_all();
- if (!keventd_up() || current_is_keventd())
- info.task.func(&info.task);
- else {
- schedule_work(&info.task);
- wait_for_completion(&done);
- }
+
+ do_boot_cpu(apicid, cpu);
}

static int boot_cpu_logical_apicid;
--
1.5.0.6

2008-03-19 20:10:37

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 70/79] [PATCH] additions to i386 native_smp_prepare_cpus.

From: Glauber Costa <[email protected]>

Add function calls to native_smp_prepare_cpus in i386
to match x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 22 +++++++++++++++++++---
1 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index d153d84..6be36d3 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -172,11 +172,23 @@ static int __init smp_sanity_check(unsigned max_cpus)
return 0;
}

-/* These are wrappers to interface to the new boot process. Someone
- who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
+static void __init smp_cpu_index_default(void)
+{
+ int i;
+ struct cpuinfo_x86 *c;
+
+ for_each_cpu_mask(i, cpu_possible_map) {
+ c = &cpu_data(i);
+ /* mark all to hotplug */
+ c->cpu_index = NR_CPUS;
+ }
+}
+
void __init native_smp_prepare_cpus(unsigned int max_cpus)
{
nmi_watchdog_default();
+ smp_cpu_index_default();
+ current_cpu_data = boot_cpu_data;
cpu_callin_map = cpumask_of_cpu(0);
mb();

@@ -195,7 +207,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
return;
}

- boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
+ if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
+ panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
+ GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
+ /* Or can we switch back to PIC here? */
+ }

connect_bsp_APIC();
setup_local_APIC();
--
1.5.0.6

2008-03-19 20:11:03

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 37/79] [PATCH] include smpboot_hooks.h in smpboot_64.c

From: Glauber Costa <[email protected]>

We do it and also fix conflicts, which makes x86_64 automatically
closer to i386

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 29 +++--------------------------
1 files changed, 3 insertions(+), 26 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index c6c993f..b9384b3 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -61,6 +61,7 @@
#include <asm/numa.h>

#include <mach_wakecpu.h>
+#include <smpboot_hooks.h>

/* Set when the idlers are all forked */
int smp_threads_ready;
@@ -517,14 +518,7 @@ do_rest:

Dprintk("Setting warm reset code and vector.\n");

- CMOS_WRITE(0xa, 0xf);
- local_flush_tlb();
- Dprintk("1.\n");
- *((volatile unsigned short *) phys_to_virt(0x469)) = start_rip >> 4;
- Dprintk("2.\n");
- *((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf;
- Dprintk("3.\n");
-
+ smpboot_setup_warm_reset_vector(start_rip);
/*
* Be paranoid about clearing APIC errors.
*/
@@ -594,23 +588,6 @@ cycles_t cacheflush_time;
unsigned long cache_decay_ticks;

/*
- * Cleanup possible dangling ends...
- */
-static __cpuinit void smp_cleanup_boot(void)
-{
- /*
- * Paranoid: Set warm reset code and vector here back
- * to default values.
- */
- CMOS_WRITE(0, 0xf);
-
- /*
- * Reset trampoline flag
- */
- *((volatile int *) phys_to_virt(0x467)) = 0;
-}
-
-/*
* Fall back to non SMP mode after errors.
*
* RED-PEN audit/test this more. I bet there is more state messed up here.
@@ -827,7 +804,7 @@ extern void smp_checks(void);
*/
void __init native_smp_cpus_done(unsigned int max_cpus)
{
- smp_cleanup_boot();
+ smpboot_restore_warm_reset_vector();

Dprintk("Boot done.\n");

--
1.5.0.6

2008-03-19 20:11:25

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 43/79] [PATCH] call nmi_watchdog_default in i386

From: Glauber Costa <[email protected]>

this does not exist, so it will be an empty macro

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 1 +
include/asm-x86/nmi.h | 4 +++-
2 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 1f3aff4..a350553 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -876,6 +876,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
void __init native_smp_prepare_cpus(unsigned int max_cpus)
{
+ nmi_watchdog_default();
smp_commenced_mask = cpumask_of_cpu(0);
cpu_callin_map = cpumask_of_cpu(0);
mb();
diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h
index 2b94199..1e36302 100644
--- a/include/asm-x86/nmi.h
+++ b/include/asm-x86/nmi.h
@@ -39,6 +39,9 @@ static inline void unset_nmi_pm_callback(struct pm_dev *dev)
#ifdef CONFIG_X86_64
extern void default_do_nmi(struct pt_regs *);
extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
+extern void nmi_watchdog_default(void);
+#else
+#define nmi_watchdog_default() do {} while (0)
#endif

extern int check_nmi_watchdog(void);
@@ -50,7 +53,6 @@ extern int reserve_perfctr_nmi(unsigned int);
extern void release_perfctr_nmi(unsigned int);
extern int reserve_evntsel_nmi(unsigned int);
extern void release_evntsel_nmi(unsigned int);
-extern void nmi_watchdog_default(void);

extern void setup_apic_nmi_watchdog(void *);
extern void stop_apic_nmi_watchdog(void *);
--
1.5.0.6

2008-03-19 20:11:41

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 49/79] [PATCH] get rid of commenced mask.

From: Glauber Costa <[email protected]>

As we now boot cpus from cpu_up, we don't need it.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 978e137..c30abed 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -59,8 +59,6 @@
#include <asm/vmi.h>
#include <asm/mtrr.h>

-static cpumask_t smp_commenced_mask;
-
/* which logical CPU number maps to which CPU (physical APIC ID) */
u16 x86_cpu_to_apicid_init[NR_CPUS] __initdata =
{ [0 ... NR_CPUS-1] = BAD_APICID };
@@ -180,8 +178,6 @@ static void __cpuinit start_secondary(void *unused)
cpu_init();
preempt_disable();
smp_callin();
- while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
- cpu_relax();

/* otherwise gcc will move up smp_processor_id before the cpu_init */
barrier();
@@ -667,7 +663,6 @@ void cpu_exit_clear(void)
cpu_clear(cpu, cpu_callout_map);
cpu_clear(cpu, cpu_callin_map);

- cpu_clear(cpu, smp_commenced_mask);
unmap_cpu_to_logical_apicid(cpu);
}
#endif
@@ -827,7 +822,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
void __init native_smp_prepare_cpus(unsigned int max_cpus)
{
nmi_watchdog_default();
- smp_commenced_mask = cpumask_of_cpu(0);
cpu_callin_map = cpumask_of_cpu(0);
mb();
smp_boot_cpus(max_cpus);
@@ -869,8 +863,6 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return -EIO;
}

- /* Unleash the CPU! */
- cpu_set(cpu, smp_commenced_mask);

/*
* Check TSC synchronization with the AP (keep irqs disabled
--
1.5.0.6

2008-03-19 20:07:00

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 57/79] [PATCH] call do_boot_cpu directly from native_cpu_up

From: Glauber Costa <[email protected]>

We don't need __smp_prepare_cpu anymore.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 21 ++++++---------------
1 files changed, 6 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5165b11..4ba5ab2 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -702,20 +702,6 @@ void cpu_exit_clear(void)
}
#endif

-static void __cpuinit __smp_prepare_cpu(int cpu)
-{
- int apicid;
-
- apicid = per_cpu(x86_cpu_to_apicid, cpu);
-
- /* init low mem mapping */
- clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
- flush_tlb_all();
-
- do_boot_cpu(apicid, cpu);
-}
-
static int boot_cpu_logical_apicid;
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio;
@@ -872,7 +858,12 @@ int __cpuinit native_cpu_up(unsigned int cpu)

per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;

- __smp_prepare_cpu(cpu);
+ /* init low mem mapping */
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+ flush_tlb_all();
+
+ do_boot_cpu(apicid, cpu);

/* In case one didn't come up */
if (!cpu_isset(cpu, cpu_callin_map)) {
--
1.5.0.6

2008-03-19 20:08:34

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 19/79] [PATCH] isolate logic to disable smp

From: Glauber Costa <[email protected]>

Put it in a disable_smp() function, as x86_64 does

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 32 ++++++++++++++++----------------
1 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index b44a743..8144aa3 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -742,6 +742,15 @@ void *xquad_portio;
EXPORT_SYMBOL(xquad_portio);
#endif

+static void __init disable_smp(void)
+{
+ smpboot_clear_io_apic_irqs();
+ phys_cpu_present_map = physid_mask_of_physid(0);
+ map_cpu_to_logical_apicid();
+ cpu_set(0, per_cpu(cpu_sibling_map, 0));
+ cpu_set(0, per_cpu(cpu_core_map, 0));
+}
+
static int __init smp_sanity_check(unsigned max_cpus)
{
/*
@@ -750,14 +759,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
*/
if (!smp_found_config && !acpi_lapic) {
printk(KERN_NOTICE "SMP motherboard not detected.\n");
- smpboot_clear_io_apic_irqs();
- phys_cpu_present_map = physid_mask_of_physid(0);
+ disable_smp();
if (APIC_init_uniprocessor())
printk(KERN_NOTICE "Local APIC not detected."
" Using dummy APIC emulation.\n");
- map_cpu_to_logical_apicid();
- cpu_set(0, per_cpu(cpu_sibling_map, 0));
- cpu_set(0, per_cpu(cpu_core_map, 0));
return -1;
}

@@ -779,11 +784,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
- smpboot_clear_io_apic_irqs();
- phys_cpu_present_map = physid_mask_of_physid(0);
- map_cpu_to_logical_apicid();
- cpu_set(0, per_cpu(cpu_sibling_map, 0));
- cpu_set(0, per_cpu(cpu_core_map, 0));
return -1;
}

@@ -801,11 +801,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
connect_bsp_APIC();
setup_local_APIC();
}
- smpboot_clear_io_apic_irqs();
- phys_cpu_present_map = physid_mask_of_physid(0);
- map_cpu_to_logical_apicid();
- cpu_set(0, per_cpu(cpu_sibling_map, 0));
- cpu_set(0, per_cpu(cpu_core_map, 0));
return -1;
}
return 0;
@@ -835,7 +830,12 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

set_cpu_sibling_map(0);

- smp_sanity_check(max_cpus);
+ if (smp_sanity_check(max_cpus) < 0) {
+ printk(KERN_INFO "SMP disabled\n");
+ disable_smp();
+ return;
+ }
+
connect_bsp_APIC();
setup_local_APIC();
map_cpu_to_logical_apicid();
--
1.5.0.6

2008-03-19 20:07:48

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 59/79] [PATCH] change wakeup_secondary name

From: Glauber Costa <[email protected]>

wakeup_secondary_via_INIT => wakeup_secondary_cpu.

This is to match i386, where init is not always used.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 8a59fa8..7ec9621 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -63,6 +63,7 @@
#include <mach_wakecpu.h>
#include <mach_apic.h>
#include <smpboot_hooks.h>
+#include <mach_apic.h>

/* Set when the idlers are all forked */
int smp_threads_ready;
@@ -293,7 +294,8 @@ static void __inquire_remote_apic(int apicid)
/*
* Kick the secondary to wake up.
*/
-static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
+static int __cpuinit wakeup_secondary_cpu(int phys_apicid,
+ unsigned int start_rip)
{
unsigned long send_status, accept_status = 0;
int maxlvt, num_starts, j;
@@ -534,7 +536,7 @@ do_rest:
/*
* Starting actual IPI sequence...
*/
- boot_error = wakeup_secondary_via_INIT(apicid, start_rip);
+ boot_error = wakeup_secondary_cpu(apicid, start_rip);

if (!boot_error) {
/*
--
1.5.0.6

2008-03-19 20:12:54

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 31/79] [PATCH] get rid of cpucount

From: Glauber Costa <[email protected]>

weighting a map will do.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 12 +++---------
1 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 2fea910..5c4e85c 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -166,8 +166,6 @@ static void __cpuinit smp_callin(void)
cpu_set(cpuid, cpu_callin_map);
}

-static int cpucount;
-
/*
* Activate a secondary processor.
*/
@@ -585,7 +583,6 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();

- ++cpucount;
alternatives_smp_switch(1);

/* So we see what's up */
@@ -656,7 +653,6 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
cpu_clear(cpu, cpu_possible_map);
per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
- cpucount--;
}

/* mark "stuck" area as not stuck */
@@ -672,7 +668,6 @@ void cpu_exit_clear(void)

idle_task_exit();

- cpucount --;
cpu_uninit();
irq_ctx_exit(cpu);

@@ -795,7 +790,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
return 0;
}

-
/*
* Cycle through the processors sending APIC IPIs to boot each.
*/
@@ -851,7 +845,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

if (!check_apicid_present(bit))
continue;
- if (max_cpus <= cpucount+1)
+ if (max_cpus <= cpus_weight(cpu_present_map))
continue;
/* Utterly temporary */
for (cpu = 0; cpu < NR_CPUS; cpu++)
@@ -878,7 +872,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
bogosum += cpu_data(cpu).loops_per_jiffy;
printk(KERN_INFO
"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
- cpucount+1,
+ cpus_weight(cpu_present_map),
bogosum/(500000/HZ),
(bogosum/(5000/HZ))%100);

@@ -892,7 +886,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
* approved Athlon
*/
if (tainted & TAINT_UNSAFE_SMP) {
- if (cpucount)
+ if (cpus_weight(cpu_present_map))
printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n");
else
tainted &= ~TAINT_UNSAFE_SMP;
--
1.5.0.6

2008-03-19 20:12:22

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 77/79] [PATCH] merge cpu_exit_clear

From: Glauber Costa <[email protected]>

this is the last remaining function in smpboot_32.c
Since it is i386 specific, move it around an ifdef to
smpboot.c

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 18 ++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 19 -------------------
2 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 45119d3..6a7fb13 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1207,6 +1207,24 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
}

#ifdef CONFIG_HOTPLUG_CPU
+
+# ifdef CONFIG_X86_32
+void cpu_exit_clear(void)
+{
+ int cpu = raw_smp_processor_id();
+
+ idle_task_exit();
+
+ cpu_uninit();
+ irq_ctx_exit(cpu);
+
+ cpu_clear(cpu, cpu_callout_map);
+ cpu_clear(cpu, cpu_callin_map);
+
+ unmap_cpu_to_logical_apicid(cpu);
+}
+# endif /* CONFIG_X86_32 */
+
void remove_siblinginfo(int cpu)
{
int sibling;
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 3a1b9e4..5469207 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -74,25 +74,6 @@ EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);

u8 apicid_2_node[MAX_APICID];

-extern void unmap_cpu_to_logical_apicid(int cpu);
-
-#ifdef CONFIG_HOTPLUG_CPU
-void cpu_exit_clear(void)
-{
- int cpu = raw_smp_processor_id();
-
- idle_task_exit();
-
- cpu_uninit();
- irq_ctx_exit(cpu);
-
- cpu_clear(cpu, cpu_callout_map);
- cpu_clear(cpu, cpu_callin_map);
-
- unmap_cpu_to_logical_apicid(cpu);
-}
-#endif
-
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio;
#ifdef CONFIG_X86_NUMAQ
--
1.5.0.6

2008-03-19 20:12:38

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 18/79] [PATCH] isolate sanity checking

From: Glauber Costa <[email protected]>

Isolate all sanity checking in a smp_sanity_check()
function as x86_64 does.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 57 ++++++++++++++++++++++-------------------
1 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index a232f4d..b44a743 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -735,10 +735,6 @@ exit:
}
#endif

-/*
- * Cycle through the processors sending APIC IPIs to boot each.
- */
-
static int boot_cpu_logical_apicid;
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio;
@@ -746,26 +742,8 @@ void *xquad_portio;
EXPORT_SYMBOL(xquad_portio);
#endif

-static void __init smp_boot_cpus(unsigned int max_cpus)
+static int __init smp_sanity_check(unsigned max_cpus)
{
- int apicid, cpu, bit, kicked;
- unsigned long bogosum = 0;
-
- /*
- * Setup boot CPU information
- */
- smp_store_cpu_info(0); /* Final full version of the data */
- printk("CPU%d: ", 0);
- print_cpu_info(&cpu_data(0));
-
- boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
- boot_cpu_logical_apicid = logical_smp_processor_id();
- per_cpu(x86_cpu_to_apicid, 0) = boot_cpu_physical_apicid;
-
- current_thread_info()->cpu = 0;
-
- set_cpu_sibling_map(0);
-
/*
* If we couldn't find an SMP configuration at boot time,
* get out of here now!
@@ -780,7 +758,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
map_cpu_to_logical_apicid();
cpu_set(0, per_cpu(cpu_sibling_map, 0));
cpu_set(0, per_cpu(cpu_core_map, 0));
- return;
+ return -1;
}

/*
@@ -806,7 +784,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
map_cpu_to_logical_apicid();
cpu_set(0, per_cpu(cpu_sibling_map, 0));
cpu_set(0, per_cpu(cpu_core_map, 0));
- return;
+ return -1;
}

verify_local_APIC();
@@ -828,9 +806,36 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
map_cpu_to_logical_apicid();
cpu_set(0, per_cpu(cpu_sibling_map, 0));
cpu_set(0, per_cpu(cpu_core_map, 0));
- return;
+ return -1;
}
+ return 0;
+}
+
+
+/*
+ * Cycle through the processors sending APIC IPIs to boot each.
+ */
+static void __init smp_boot_cpus(unsigned int max_cpus)
+{
+ int apicid, cpu, bit, kicked;
+ unsigned long bogosum = 0;
+
+ /*
+ * Setup boot CPU information
+ */
+ smp_store_cpu_info(0); /* Final full version of the data */
+ printk(KERN_INFO "CPU%d: ", 0);
+ print_cpu_info(&cpu_data(0));
+
+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
+ boot_cpu_logical_apicid = logical_smp_processor_id();
+ per_cpu(x86_cpu_to_apicid, 0) = boot_cpu_physical_apicid;
+
+ current_thread_info()->cpu = 0;
+
+ set_cpu_sibling_map(0);

+ smp_sanity_check(max_cpus);
connect_bsp_APIC();
setup_local_APIC();
map_cpu_to_logical_apicid();
--
1.5.0.6

2008-03-19 20:11:57

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 23/79] [PATCH] unify extern masks declaration

From: Glauber Costa <[email protected]>

take them off smp_{32,64}.h and move to smp.h

Signed-off-by: Glauber Costa <[email protected]>
---
include/asm-x86/smp.h | 12 ++++++++++++
include/asm-x86/smp_32.h | 8 --------
include/asm-x86/smp_64.h | 11 -----------
3 files changed, 12 insertions(+), 19 deletions(-)

diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index b4c5143..d02e6ea 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -3,12 +3,24 @@
#ifndef __ASSEMBLY__
#include <linux/cpumask.h>
#include <linux/init.h>
+#include <asm/percpu.h>

extern cpumask_t cpu_callout_map;

extern int smp_num_siblings;
extern unsigned int num_processors;

+extern u16 x86_cpu_to_apicid_init[];
+extern u16 x86_bios_cpu_apicid_init[];
+extern void *x86_cpu_to_apicid_early_ptr;
+extern void *x86_bios_cpu_apicid_early_ptr;
+
+DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
+DECLARE_PER_CPU(cpumask_t, cpu_core_map);
+DECLARE_PER_CPU(u16, cpu_llc_id);
+DECLARE_PER_CPU(u16, x86_cpu_to_apicid);
+DECLARE_PER_CPU(u16, x86_bios_cpu_apicid);
+
/*
* Trampoline 80x86 program as an array.
*/
diff --git a/include/asm-x86/smp_32.h b/include/asm-x86/smp_32.h
index 51624ab..478f556 100644
--- a/include/asm-x86/smp_32.h
+++ b/include/asm-x86/smp_32.h
@@ -21,14 +21,6 @@ extern cpumask_t cpu_callin_map;
extern void (*mtrr_hook) (void);
extern void zap_low_mappings (void);

-extern u16 __initdata x86_cpu_to_apicid_init[];
-extern void *x86_cpu_to_apicid_early_ptr;
-
-DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
-DECLARE_PER_CPU(cpumask_t, cpu_core_map);
-DECLARE_PER_CPU(u16, cpu_llc_id);
-DECLARE_PER_CPU(u16, x86_cpu_to_apicid);
-
#ifdef CONFIG_SMP
/*
* This function is needed by all SMP systems. It must _always_ be valid
diff --git a/include/asm-x86/smp_64.h b/include/asm-x86/smp_64.h
index 394c785..1b3c0f1 100644
--- a/include/asm-x86/smp_64.h
+++ b/include/asm-x86/smp_64.h
@@ -19,17 +19,6 @@ extern cpumask_t cpu_callin_map;
extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
void *info, int wait);

-extern u16 __initdata x86_cpu_to_apicid_init[];
-extern u16 __initdata x86_bios_cpu_apicid_init[];
-extern void *x86_cpu_to_apicid_early_ptr;
-extern void *x86_bios_cpu_apicid_early_ptr;
-
-DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
-DECLARE_PER_CPU(cpumask_t, cpu_core_map);
-DECLARE_PER_CPU(u16, cpu_llc_id);
-DECLARE_PER_CPU(u16, x86_cpu_to_apicid);
-DECLARE_PER_CPU(u16, x86_bios_cpu_apicid);
-
static inline int cpu_present_to_apicid(int mps_cpu)
{
if (cpu_present(mps_cpu))
--
1.5.0.6

2008-03-19 20:14:30

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 72/79] [PATCH] change x86_64 native_smp_prepare_cpus to match i386

From: Glauber Costa <[email protected]>

An APIC test is moved, and code is replaced by the mach-default
already defined function (smpboot_setup_io_apic).
setup_portio_remap() is added, but it is a nop in mach-default.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 24 ++++++++++--------------
1 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index f4363a3..6679ac5 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -71,6 +71,7 @@ int smp_threads_ready;
cycles_t cacheflush_time;
unsigned long cache_decay_ticks;

+static int boot_cpu_logical_apicid;
/*
* Fall back to non SMP mode after errors.
*
@@ -167,7 +168,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
{
nmi_watchdog_default();
smp_cpu_index_default();
+ cpu_callin_map = cpumask_of_cpu(0);
+ mb();
+
current_cpu_data = boot_cpu_data;
+ boot_cpu_logical_apicid = logical_smp_processor_id();
current_thread_info()->cpu = 0; /* needed? */
set_cpu_sibling_map(0);

@@ -177,6 +182,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
return;
}

+ if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
+ panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
+ GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
+ /* Or can we switch back to PIC here? */
+ }

/*
* Switch from PIC to APIC mode.
@@ -190,20 +200,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
enable_IO_APIC();
end_local_APIC_setup();

- if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
- panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
- GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
- /* Or can we switch back to PIC here? */
- }
-
- /*
- * Now start the IO-APICs
- */
- if (!skip_ioapic_setup && nr_ioapics)
- setup_IO_APIC();
- else
- nr_ioapics = 0;
-
/*
* Set up local APIC timer on boot CPU.
*/
--
1.5.0.6

2008-03-19 20:15:26

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 74/79] [PATCH] change x86_64 sanity checks to match i386.

From: Glauber Costa <[email protected]>

They are mostly inocuous. APIC_INTEGRATED will expand to 1,
check_phys_apicid_present is checking for the same thing it was before,
etc. But the code is identical to i386 now, and will allow us to
integrate it.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_64.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 6679ac5..c66fb15 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -50,6 +50,7 @@
#include <linux/smp.h>
#include <linux/kdebug.h>

+#include <asm/acpi.h>
#include <asm/mtrr.h>
#include <asm/pgalloc.h>
#include <asm/desc.h>
@@ -105,7 +106,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
* If we couldn't find an SMP configuration at boot time,
* get out of here now!
*/
- if (!smp_found_config) {
+ if (!smp_found_config && !acpi_lapic) {
printk(KERN_NOTICE "SMP motherboard not detected.\n");
disable_smp();
if (APIC_init_uniprocessor())
@@ -118,7 +119,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
* Should not be necessary because the MP table should list the boot
* CPU too, but we do it for the sake of robustness anyway.
*/
- if (!physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map)) {
+ if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
printk(KERN_NOTICE
"weird, boot CPU (#%d) not listed by the BIOS.\n",
boot_cpu_physical_apicid);
@@ -128,7 +129,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
/*
* If we couldn't find a local APIC, then get out of here now!
*/
- if (!cpu_has_apic) {
+ if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) &&
+ !cpu_has_apic) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
@@ -136,6 +138,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
return -1;
}

+ verify_local_APIC();
+
/*
* If SMP should be disabled, then really disable it!
*/
--
1.5.0.6

2008-03-19 20:13:26

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 32/79] [PATCH] allow user to impress friends.

From: Glauber Costa <[email protected]>

Impressing friends is a very important thing.
Do it in a separate function to make it even more
explicit, and ease integration.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 20 ++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 17 ++---------------
2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index a157a52..02427d1 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -228,6 +228,26 @@ void __init smp_alloc_memory(void)
}
#endif

+void impress_friends(void)
+{
+ int cpu;
+ unsigned long bogosum = 0;
+ /*
+ * Allow the user to impress friends.
+ */
+ Dprintk("Before bogomips.\n");
+ for_each_possible_cpu(cpu)
+ if (cpu_isset(cpu, cpu_callout_map))
+ bogosum += cpu_data(cpu).loops_per_jiffy;
+ printk(KERN_INFO
+ "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+ cpus_weight(cpu_present_map),
+ bogosum/(500000/HZ),
+ (bogosum/(5000/HZ))%100);
+
+ Dprintk("Before bogocount - setting activated=1.\n");
+}
+
#ifdef CONFIG_HOTPLUG_CPU
void remove_siblinginfo(int cpu)
{
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5c4e85c..34493f8 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -790,13 +790,13 @@ static int __init smp_sanity_check(unsigned max_cpus)
return 0;
}

+extern void impress_friends(void);
/*
* Cycle through the processors sending APIC IPIs to boot each.
*/
static void __init smp_boot_cpus(unsigned int max_cpus)
{
int apicid, cpu, bit, kicked;
- unsigned long bogosum = 0;

/*
* Setup boot CPU information
@@ -863,20 +863,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
*/
smpboot_restore_warm_reset_vector();

- /*
- * Allow the user to impress friends.
- */
- Dprintk("Before bogomips.\n");
- for_each_possible_cpu(cpu)
- if (cpu_isset(cpu, cpu_callout_map))
- bogosum += cpu_data(cpu).loops_per_jiffy;
- printk(KERN_INFO
- "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
- cpus_weight(cpu_present_map),
- bogosum/(500000/HZ),
- (bogosum/(5000/HZ))%100);
-
- Dprintk("Before bogocount - setting activated=1.\n");
+ impress_friends();

if (smp_b_stepping)
printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
--
1.5.0.6

2008-03-19 20:13:42

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 38/79] [PATCH] move smp_intr_init away from smpboot_32.c

From: Glauber Costa <[email protected]>

We move it to apic_32.c, since it's irq related anyway,
and only called from that file.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/apic_32.c | 23 +++++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 21 ---------------------
2 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 6aa93db..c32cc0f 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -1317,6 +1317,29 @@ void smp_error_interrupt(struct pt_regs *regs)
irq_exit();
}

+#ifdef CONFIG_SMP
+void __init smp_intr_init(void)
+{
+ /*
+ * IRQ0 must be given a fixed assignment and initialized,
+ * because it's used before the IO-APIC is set up.
+ */
+ set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+
+ /*
+ * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+ * IPI, driven by wakeup.
+ */
+ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+
+ /* IPI for invalidation */
+ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+
+ /* IPI for generic function call */
+ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+}
+#endif
+
/*
* Initialize APIC interrupts
*/
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 1736404..87c9a75 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -968,24 +968,3 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
#endif
zap_low_mappings();
}
-
-void __init smp_intr_init(void)
-{
- /*
- * IRQ0 must be given a fixed assignment and initialized,
- * because it's used before the IO-APIC is set up.
- */
- set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
-
- /*
- * The reschedule interrupt is a CPU-to-CPU reschedule-helper
- * IPI, driven by wakeup.
- */
- set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
-
- /* IPI for invalidation */
- set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
-
- /* IPI for generic function call */
- set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-}
--
1.5.0.6

2008-03-19 20:14:00

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 54/79] [PATCH] provide an end_local_APIC_setup function

From: Glauber Costa <[email protected]>

It splits setup_local_APIC in two, providing a function corresponding
to the ending part of it. As a side effect, smp_callin looks the same
between i386 and x86_64.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/apic_32.c | 7 ++++++-
arch/x86/kernel/smpboot_32.c | 3 +++
2 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 80c81c7..6f50602 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -1064,9 +1064,13 @@ void __cpuinit setup_local_APIC(void)
if (!integrated) /* 82489DX */
value |= APIC_LVT_LEVEL_TRIGGER;
apic_write_around(APIC_LVT1, value);
+}

- lapic_setup_esr();
+void __cpuinit end_local_APIC_setup(void)
+{
+ unsigned long value;

+ lapic_setup_esr();
/* Disable the local apic timer */
value = apic_read(APIC_LVTT);
value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
@@ -1256,6 +1260,7 @@ int __init APIC_init_uniprocessor(void)

setup_local_APIC();

+ end_local_APIC_setup();
#ifdef CONFIG_X86_IO_APIC
if (smp_found_config)
if (!skip_ioapic_setup && nr_ioapics)
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index c03596e..dbfaeb3 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -161,6 +161,7 @@ static void __cpuinit smp_callin(void)
Dprintk("CALLIN, before setup_local_APIC().\n");
smp_callin_clear_local_apic();
setup_local_APIC();
+ end_local_APIC_setup();
map_cpu_to_logical_apicid();

/*
@@ -780,6 +781,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
printk(KERN_INFO "activating minimal APIC for NMI watchdog use.\n");
connect_bsp_APIC();
setup_local_APIC();
+ end_local_APIC_setup();
}
return -1;
}
@@ -813,6 +815,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

connect_bsp_APIC();
setup_local_APIC();
+ end_local_APIC_setup();
map_cpu_to_logical_apicid();


--
1.5.0.6

2008-03-19 20:15:50

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 62/79] [PATCH] move stack_start to smp.h

From: Glauber Costa <[email protected]>

voyager would conflict with it, but the types are ultimately
compatible. So remove the extern definition from voyager_smp.c
in favour of the common one

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 6 ------
arch/x86/mach-voyager/voyager_smp.c | 7 -------
include/asm-x86/smp.h | 7 +++++++
3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 1eb7b73..ae25927 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -257,12 +257,6 @@ void __devinit initialize_secondary(void)
:"m" (current->thread.sp),"m" (current->thread.ip));
}

-/* Static state in head.S used to set up a CPU */
-extern struct {
- void * sp;
- unsigned short ss;
-} stack_start;
-
static inline void __inquire_remote_apic(int apicid)
{
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c
index 5d4c185..a707712 100644
--- a/arch/x86/mach-voyager/voyager_smp.c
+++ b/arch/x86/mach-voyager/voyager_smp.c
@@ -518,13 +518,6 @@ static void __init do_boot_cpu(__u8 cpu)
& ~(voyager_extended_vic_processors
& voyager_allowed_boot_processors);

- /* This is an area in head.S which was used to set up the
- * initial kernel stack. We need to alter this to give the
- * booting CPU a new stack (taken from its idle process) */
- extern struct {
- __u8 *sp;
- unsigned short ss;
- } stack_start;
/* This is the format of the CPI IDT gate (in real mode) which
* we're hijacking to boot the CPU */
union IDTFormat {
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index d02e6ea..78ef16d 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -28,6 +28,13 @@ extern const unsigned char trampoline_data [];
extern const unsigned char trampoline_end [];
extern unsigned char *trampoline_base;

+/* Static state in head.S used to set up a CPU */
+extern struct {
+ void *sp;
+ unsigned short ss;
+} stack_start;
+
+
struct smp_ops {
void (*smp_prepare_boot_cpu)(void);
void (*smp_prepare_cpus)(unsigned max_cpus);
--
1.5.0.6

2008-03-19 20:16:44

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 78/79] [PATCH] move apicid mappings to smpboot.c

From: Glauber Costa <[email protected]>

They are i386 specific (the x86_64 definitions live
elsewhere, and should remain there), so are enclosed around
an ifdef

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 21 +++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 13 -------------
2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6a7fb13..75637fb 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -25,6 +25,27 @@
#include <mach_wakecpu.h>
#include <smpboot_hooks.h>

+/*
+ * FIXME: For x86_64, those are defined in other files. But moving them here,
+ * would make the setup areas dependent on smp, which is a loss. When we
+ * integrate apic between arches, we can probably do a better job, but
+ * right now, they'll stay here -- glommer
+ */
+#ifdef CONFIG_X86_32
+/* which logical CPU number maps to which CPU (physical APIC ID) */
+u16 x86_cpu_to_apicid_init[NR_CPUS] __initdata =
+ { [0 ... NR_CPUS-1] = BAD_APICID };
+void *x86_cpu_to_apicid_early_ptr;
+DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID;
+EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid);
+
+u16 x86_bios_cpu_apicid_init[NR_CPUS] __initdata
+ = { [0 ... NR_CPUS-1] = BAD_APICID };
+void *x86_bios_cpu_apicid_early_ptr;
+DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
+EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
+#endif
+
/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5469207..3590afe 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -59,19 +59,6 @@
#include <asm/vmi.h>
#include <asm/mtrr.h>

-/* which logical CPU number maps to which CPU (physical APIC ID) */
-u16 x86_cpu_to_apicid_init[NR_CPUS] __initdata =
- { [0 ... NR_CPUS-1] = BAD_APICID };
-void *x86_cpu_to_apicid_early_ptr;
-DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID;
-EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid);
-
-u16 x86_bios_cpu_apicid_init[NR_CPUS] __initdata
- = { [0 ... NR_CPUS-1] = BAD_APICID };
-void *x86_bios_cpu_apicid_early_ptr;
-DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
-EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
-
u8 apicid_2_node[MAX_APICID];

/* Where the IO area was mapped on multiquad, always 0 otherwise */
--
1.5.0.6

2008-03-19 20:17:00

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 34/79] [PATCH] move impress_friends and smp_check to cpus_done

From: Glauber Costa <[email protected]>

the cpu count is changed accordingly: now, what matters is
online cpus.
Also, we add those functions for x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 4 ++--
arch/x86/kernel/smpboot_32.c | 22 ++++++++++++----------
arch/x86/kernel/smpboot_64.c | 8 ++++++++
3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index ddb94ef..6978f1b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -114,7 +114,7 @@ void smp_checks(void)
* approved Athlon
*/
if (tainted & TAINT_UNSAFE_SMP) {
- if (cpus_weight(cpu_present_map))
+ if (num_online_cpus())
printk(KERN_INFO "WARNING: This combination of AMD"
"processors is not suitable for SMP.\n");
else
@@ -258,7 +258,7 @@ void impress_friends(void)
bogosum += cpu_data(cpu).loops_per_jiffy;
printk(KERN_INFO
"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
- cpus_weight(cpu_present_map),
+ num_online_cpus(),
bogosum/(500000/HZ),
(bogosum/(5000/HZ))%100);

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 361851c..1736404 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -788,8 +788,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
return 0;
}

-extern void impress_friends(void);
-extern void smp_checks(void);
/*
* Cycle through the processors sending APIC IPIs to boot each.
*/
@@ -858,14 +856,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
}

/*
- * Cleanup possible dangling ends...
- */
- smpboot_restore_warm_reset_vector();
-
- impress_friends();
-
- smp_checks();
- /*
* construct cpu_sibling_map, so that we can tell sibling CPUs
* efficiently.
*/
@@ -959,8 +949,20 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return 0;
}

+extern void impress_friends(void);
+extern void smp_checks(void);
+
void __init native_smp_cpus_done(unsigned int max_cpus)
{
+ /*
+ * Cleanup possible dangling ends...
+ */
+ smpboot_restore_warm_reset_vector();
+
+ Dprintk("Boot done.\n");
+
+ impress_friends();
+ smp_checks();
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
#endif
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index a9cc911..c3e770b 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -824,12 +824,20 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return err;
}

+extern void impress_friends(void);
+extern void smp_checks(void);
+
/*
* Finish the SMP boot.
*/
void __init native_smp_cpus_done(unsigned int max_cpus)
{
smp_cleanup_boot();
+
+ Dprintk("Boot done.\n");
+
+ impress_friends();
+ smp_checks();
setup_ioapic_dest();
check_nmi_watchdog();
}
--
1.5.0.6

2008-03-19 20:18:36

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 75/79] [PATCH] introduce smpboot_clear_io_apic

From: Glauber Costa <[email protected]>

x86_64 has two nr_ioapics = 0 statements. In 32-bit, it can be done
too. We do it through the smpboot_clear_io_apic() inline function,
to cope with subarchitectures (visws) that does not compile mpparse in

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 2 ++
arch/x86/kernel/smpboot_64.c | 4 ++--
include/asm-x86/mach-default/smpboot_hooks.h | 5 +++++
include/asm-x86/mach-visws/smpboot_hooks.h | 4 ++++
4 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index ae23b60..5a0f57f 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -155,6 +155,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
+ smpboot_clear_io_apic();
return -1;
}

@@ -173,6 +174,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
setup_local_APIC();
end_local_APIC_setup();
}
+ smpboot_clear_io_apic();
return -1;
}
return 0;
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index c66fb15..7752445 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -134,7 +134,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
- nr_ioapics = 0;
+ smpboot_clear_io_apic();
return -1;
}

@@ -145,7 +145,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
*/
if (!max_cpus) {
printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
- nr_ioapics = 0;
+ smpboot_clear_io_apic();
return -1;
}

diff --git a/include/asm-x86/mach-default/smpboot_hooks.h b/include/asm-x86/mach-default/smpboot_hooks.h
index 8e1c6c0..3ff2c5b 100644
--- a/include/asm-x86/mach-default/smpboot_hooks.h
+++ b/include/asm-x86/mach-default/smpboot_hooks.h
@@ -44,3 +44,8 @@ static inline void smpboot_setup_io_apic(void)
else
nr_ioapics = 0;
}
+
+static inline void smpboot_clear_io_apic(void)
+{
+ nr_ioapics = 0;
+}
diff --git a/include/asm-x86/mach-visws/smpboot_hooks.h b/include/asm-x86/mach-visws/smpboot_hooks.h
index d926471..c9b83e3 100644
--- a/include/asm-x86/mach-visws/smpboot_hooks.h
+++ b/include/asm-x86/mach-visws/smpboot_hooks.h
@@ -22,3 +22,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
static inline void smpboot_setup_io_apic(void)
{
}
+
+static inline void smpboot_clear_io_apic(void)
+{
+}
--
1.5.0.6

2008-03-19 20:19:07

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 48/79] [PATCH] boot cpus from cpu_up, instead of prepare_cpus

From: Glauber Costa <[email protected]>

After all the infrastructure work, we're now prepared
to boot the cpus from cpu_up, and not from prepare_cpus.
So the difference between cold boot and hotplug is effectively
over, and the functions are used to the purposes they're meant to.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 48 +----------------------------------------
1 files changed, 2 insertions(+), 46 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 88ee655..978e137 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -670,6 +670,7 @@ void cpu_exit_clear(void)
cpu_clear(cpu, smp_commenced_mask);
unmap_cpu_to_logical_apicid(cpu);
}
+#endif

struct warm_boot_cpu_info {
struct completion *complete;
@@ -710,7 +711,6 @@ static void __cpuinit __smp_prepare_cpu(int cpu)
wait_for_completion(&done);
}
}
-#endif

static int boot_cpu_logical_apicid;
/* Where the IO area was mapped on multiquad, always 0 otherwise */
@@ -790,8 +790,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
*/
static void __init smp_boot_cpus(unsigned int max_cpus)
{
- int apicid, cpu, bit, kicked;
-
/*
* Setup boot CPU information
*/
@@ -819,39 +817,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

setup_portio_remap();

- /*
- * Scan the CPU present map and fire up the other CPUs via do_boot_cpu
- *
- * In clustered apic mode, phys_cpu_present_map is a constructed thus:
- * bits 0-3 are quad0, 4-7 are quad1, etc. A perverse twist on the
- * clustered apic ID.
- */
- Dprintk("CPU present map: %lx\n", physids_coerce(phys_cpu_present_map));
-
- kicked = 1;
- for (bit = 0; kicked < NR_CPUS && bit < MAX_APICS; bit++) {
- apicid = cpu_present_to_apicid(bit);
- /*
- * Don't even attempt to start the boot CPU!
- */
- if ((apicid == boot_cpu_apicid) || (apicid == BAD_APICID))
- continue;
-
- if (!check_apicid_present(bit))
- continue;
- if (max_cpus <= cpus_weight(cpu_present_map))
- continue;
- /* Utterly temporary */
- for (cpu = 0; cpu < NR_CPUS; cpu++)
- if (per_cpu(x86_cpu_to_apicid, cpu) == apicid)
- break;
- if (do_boot_cpu(apicid, cpu))
- printk("CPU #%d not responding - cannot use it.\n",
- apicid);
- else
- ++kicked;
- }
-
smpboot_setup_io_apic();

setup_boot_clock();
@@ -895,17 +860,8 @@ int __cpuinit native_cpu_up(unsigned int cpu)
}

per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
-#ifdef CONFIG_HOTPLUG_CPU

- /*
- * We do warm boot only on cpus that had booted earlier
- * Otherwise cold boot is all handled from smp_boot_cpus().
- * cpu_callin_map is set during AP kickstart process. Its reset
- * when a cpu is taken offline from cpu_exit_clear().
- */
- if (!cpu_isset(cpu, cpu_callin_map))
- __smp_prepare_cpu(cpu);
-#endif
+ __smp_prepare_cpu(cpu);

/* In case one didn't come up */
if (!cpu_isset(cpu, cpu_callin_map)) {
--
1.5.0.6

2008-03-19 20:20:51

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 24/79] [PATCH] define bios to apicid mapping

From: Glauber Costa <[email protected]>

This mapping already exists in x86_64, just provide it for
i386

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 6 ++++++
include/asm-x86/mach-bigsmp/mach_apic.h | 7 ++-----
include/asm-x86/mach-es7000/mach_apic.h | 8 +++-----
include/asm-x86/mach-summit/mach_apic.h | 3 +--
4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 0e86ccc..92a5df6 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -70,6 +70,12 @@ void *x86_cpu_to_apicid_early_ptr;
DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID;
EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid);

+u16 x86_bios_cpu_apicid_init[NR_CPUS] __initdata
+ = { [0 ... NR_CPUS-1] = BAD_APICID };
+void *x86_bios_cpu_apicid_early_ptr;
+DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
+EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
+
u8 apicid_2_node[MAX_APICID];

static void map_cpu_to_logical_apicid(void);
diff --git a/include/asm-x86/mach-bigsmp/mach_apic.h b/include/asm-x86/mach-bigsmp/mach_apic.h
index 6df235e..0d55b1f 100644
--- a/include/asm-x86/mach-bigsmp/mach_apic.h
+++ b/include/asm-x86/mach-bigsmp/mach_apic.h
@@ -1,10 +1,7 @@
#ifndef __ASM_MACH_APIC_H
#define __ASM_MACH_APIC_H

-
-extern u8 bios_cpu_apicid[];
-
-#define xapic_phys_to_log_apicid(cpu) (bios_cpu_apicid[cpu])
+#define xapic_phys_to_log_apicid(cpu) (per_cpu(x86_bios_cpu_apicid, cpu))
#define esr_disable (1)

static inline int apic_id_registered(void)
@@ -90,7 +87,7 @@ static inline int apicid_to_node(int logical_apicid)
static inline int cpu_present_to_apicid(int mps_cpu)
{
if (mps_cpu < NR_CPUS)
- return (int) bios_cpu_apicid[mps_cpu];
+ return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);

return BAD_APICID;
}
diff --git a/include/asm-x86/mach-es7000/mach_apic.h b/include/asm-x86/mach-es7000/mach_apic.h
index d23011f..04cba9f 100644
--- a/include/asm-x86/mach-es7000/mach_apic.h
+++ b/include/asm-x86/mach-es7000/mach_apic.h
@@ -1,9 +1,7 @@
#ifndef __ASM_MACH_APIC_H
#define __ASM_MACH_APIC_H

-extern u8 bios_cpu_apicid[];
-
-#define xapic_phys_to_log_apicid(cpu) (bios_cpu_apicid[cpu])
+#define xapic_phys_to_log_apicid(cpu) per_cpu(x86_bios_cpu_apicid, cpu)
#define esr_disable (1)

static inline int apic_id_registered(void)
@@ -80,7 +78,7 @@ extern void enable_apic_mode(void);
extern int apic_version [MAX_APICS];
static inline void setup_apic_routing(void)
{
- int apic = bios_cpu_apicid[smp_processor_id()];
+ int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
printk("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n",
(apic_version[apic] == 0x14) ?
"Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(TARGET_CPUS)[0]);
@@ -102,7 +100,7 @@ static inline int cpu_present_to_apicid(int mps_cpu)
if (!mps_cpu)
return boot_cpu_physical_apicid;
else if (mps_cpu < NR_CPUS)
- return (int) bios_cpu_apicid[mps_cpu];
+ return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
else
return BAD_APICID;
}
diff --git a/include/asm-x86/mach-summit/mach_apic.h b/include/asm-x86/mach-summit/mach_apic.h
index 062c97f..91d7641 100644
--- a/include/asm-x86/mach-summit/mach_apic.h
+++ b/include/asm-x86/mach-summit/mach_apic.h
@@ -40,7 +40,6 @@ static inline unsigned long check_apicid_present(int bit)

#define apicid_cluster(apicid) ((apicid) & XAPIC_DEST_CLUSTER_MASK)

-extern u8 bios_cpu_apicid[];
extern u8 cpu_2_logical_apicid[];

static inline void init_apic_ldr(void)
@@ -110,7 +109,7 @@ static inline int cpu_to_logical_apicid(int cpu)
static inline int cpu_present_to_apicid(int mps_cpu)
{
if (mps_cpu < NR_CPUS)
- return (int)bios_cpu_apicid[mps_cpu];
+ return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
else
return BAD_APICID;
}
--
1.5.0.6

2008-03-19 20:21:16

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 53/79] [PATCH] wrap esr setting up in i386 in lapic_setup_esr

From: Glauber Costa <[email protected]>

it is a little bit more complicated than x86_64 due to erratas and
other stuff, but its existance will ease integration

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/apic_32.c | 73 ++++++++++++++++++++++++--------------------
1 files changed, 40 insertions(+), 33 deletions(-)

diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index c32cc0f..80c81c7 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -897,12 +897,50 @@ void __init init_bsp_APIC(void)
apic_write_around(APIC_LVT1, value);
}

+void __cpuinit lapic_setup_esr(void)
+{
+ unsigned long oldvalue, value, maxlvt;
+ if (lapic_is_integrated() && !esr_disable) {
+ /* !82489DX */
+ maxlvt = lapic_get_maxlvt();
+ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
+ apic_write(APIC_ESR, 0);
+ oldvalue = apic_read(APIC_ESR);
+
+ /* enables sending errors */
+ value = ERROR_APIC_VECTOR;
+ apic_write_around(APIC_LVTERR, value);
+ /*
+ * spec says clear errors after enabling vector.
+ */
+ if (maxlvt > 3)
+ apic_write(APIC_ESR, 0);
+ value = apic_read(APIC_ESR);
+ if (value != oldvalue)
+ apic_printk(APIC_VERBOSE, "ESR value before enabling "
+ "vector: 0x%08lx after: 0x%08lx\n",
+ oldvalue, value);
+ } else {
+ if (esr_disable)
+ /*
+ * Something untraceable is creating bad interrupts on
+ * secondary quads ... for the moment, just leave the
+ * ESR disabled - we can't do anything useful with the
+ * errors anyway - mbligh
+ */
+ printk(KERN_INFO "Leaving ESR disabled.\n");
+ else
+ printk(KERN_INFO "No ESR for 82489DX.\n");
+ }
+}
+
+
/**
* setup_local_APIC - setup the local APIC
*/
void __cpuinit setup_local_APIC(void)
{
- unsigned long oldvalue, value, maxlvt, integrated;
+ unsigned long value, integrated;
int i, j;

/* Pound the ESR really hard over the head with a big hammer - mbligh */
@@ -1027,38 +1065,7 @@ void __cpuinit setup_local_APIC(void)
value |= APIC_LVT_LEVEL_TRIGGER;
apic_write_around(APIC_LVT1, value);

- if (integrated && !esr_disable) {
- /* !82489DX */
- maxlvt = lapic_get_maxlvt();
- if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
- apic_write(APIC_ESR, 0);
- oldvalue = apic_read(APIC_ESR);
-
- /* enables sending errors */
- value = ERROR_APIC_VECTOR;
- apic_write_around(APIC_LVTERR, value);
- /*
- * spec says clear errors after enabling vector.
- */
- if (maxlvt > 3)
- apic_write(APIC_ESR, 0);
- value = apic_read(APIC_ESR);
- if (value != oldvalue)
- apic_printk(APIC_VERBOSE, "ESR value before enabling "
- "vector: 0x%08lx after: 0x%08lx\n",
- oldvalue, value);
- } else {
- if (esr_disable)
- /*
- * Something untraceable is creating bad interrupts on
- * secondary quads ... for the moment, just leave the
- * ESR disabled - we can't do anything useful with the
- * errors anyway - mbligh
- */
- printk(KERN_INFO "Leaving ESR disabled.\n");
- else
- printk(KERN_INFO "No ESR for 82489DX.\n");
- }
+ lapic_setup_esr();

/* Disable the local apic timer */
value = apic_read(APIC_LVTT);
--
1.5.0.6

2008-03-19 20:21:39

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 21/79] [PATCH] make __smp_prepare_cpu void

From: Glauber Costa <[email protected]>

We have already removed the only condition that could fail here.
so just don't test for any return value

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 13 +++----------
1 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 147af81..ee6f3bd 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -704,11 +704,11 @@ static void __cpuinit do_warm_boot_cpu(struct work_struct *work)
complete(info->complete);
}

-static int __cpuinit __smp_prepare_cpu(int cpu)
+static void __cpuinit __smp_prepare_cpu(int cpu)
{
DECLARE_COMPLETION_ONSTACK(done);
struct warm_boot_cpu_info info;
- int apicid, ret;
+ int apicid;

apicid = per_cpu(x86_cpu_to_apicid, cpu);

@@ -725,9 +725,6 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
wait_for_completion(&done);

zap_low_mappings();
- ret = 0;
-exit:
- return ret;
}
#endif

@@ -950,7 +947,6 @@ int __cpuinit native_cpu_up(unsigned int cpu)
{
int apicid = cpu_present_to_apicid(cpu);
unsigned long flags;
- int ret = 0;

WARN_ON(irqs_disabled());

@@ -971,10 +967,7 @@ int __cpuinit native_cpu_up(unsigned int cpu)
* when a cpu is taken offline from cpu_exit_clear().
*/
if (!cpu_isset(cpu, cpu_callin_map))
- ret = __smp_prepare_cpu(cpu);
-
- if (ret)
- return -EIO;
+ __smp_prepare_cpu(cpu);
#endif

/* In case one didn't come up */
--
1.5.0.6

2008-03-19 20:18:07

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 67/79] [PATCH] merge native_smp_cpus_done

From: Glauber Costa <[email protected]>

They look similar enough, and are merged. Only difference
(zap_low_mapping for i386) is inside ifdef

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 21 ++++++++++++++++++++-
arch/x86/kernel/smpboot_32.c | 21 ---------------------
arch/x86/kernel/smpboot_64.c | 18 ------------------
3 files changed, 20 insertions(+), 40 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index b214d8d..26118b4 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -880,7 +880,6 @@ do_rest:
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);

-
/*
* Starting actual IPI sequence...
*/
@@ -1017,6 +1016,26 @@ void __init native_smp_prepare_boot_cpu(void)
per_cpu(cpu_state, me) = CPU_ONLINE;
}

+void __init native_smp_cpus_done(unsigned int max_cpus)
+{
+ /*
+ * Cleanup possible dangling ends...
+ */
+ smpboot_restore_warm_reset_vector();
+
+ Dprintk("Boot done.\n");
+
+ impress_friends();
+ smp_checks();
+#ifdef CONFIG_X86_IO_APIC
+ setup_ioapic_dest();
+#endif
+ check_nmi_watchdog();
+#ifdef CONFIG_X86_32
+ zap_low_mappings();
+#endif
+}
+
#ifdef CONFIG_HOTPLUG_CPU
void remove_siblinginfo(int cpu)
{
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5d27b1d..75fb506 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -215,24 +215,3 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
mb();
smp_boot_cpus(max_cpus);
}
-
-extern void impress_friends(void);
-extern void smp_checks(void);
-
-void __init native_smp_cpus_done(unsigned int max_cpus)
-{
- /*
- * Cleanup possible dangling ends...
- */
- smpboot_restore_warm_reset_vector();
-
- Dprintk("Boot done.\n");
-
- impress_friends();
- smp_checks();
-#ifdef CONFIG_X86_IO_APIC
- setup_ioapic_dest();
-#endif
- check_nmi_watchdog();
- zap_low_mappings();
-}
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index f77299b..f4363a3 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -212,21 +212,3 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
printk(KERN_INFO "CPU%d: ", 0);
print_cpu_info(&cpu_data(0));
}
-
-extern void impress_friends(void);
-extern void smp_checks(void);
-
-/*
- * Finish the SMP boot.
- */
-void __init native_smp_cpus_done(unsigned int max_cpus)
-{
- smpboot_restore_warm_reset_vector();
-
- Dprintk("Boot done.\n");
-
- impress_friends();
- smp_checks();
- setup_ioapic_dest();
- check_nmi_watchdog();
-}
--
1.5.0.6

2008-03-19 20:23:23

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 61/79] [PATCH] move {un}map_cpu_to_logical_apicid to smpboot.c

From: Glauber Costa <[email protected]>

Move map_cpu_to_logical_apicid() and unmap_cpu_to_logical_apicid()
to smpboot.c. They take together all the bunch of static functions
they rely upon

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 60 ++++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 59 +---------------------------------------
2 files changed, 62 insertions(+), 57 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 253be86..5bff87e 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -50,6 +50,66 @@ static cpumask_t cpu_sibling_setup_map;
/* Set if we find a B stepping CPU */
int __cpuinitdata smp_b_stepping;

+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_32)
+
+/* which logical CPUs are on which nodes */
+cpumask_t node_to_cpumask_map[MAX_NUMNODES] __read_mostly =
+ { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
+EXPORT_SYMBOL(node_to_cpumask_map);
+/* which node each logical CPU is on */
+int cpu_to_node_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
+EXPORT_SYMBOL(cpu_to_node_map);
+
+/* set up a mapping between cpu and node. */
+static void map_cpu_to_node(int cpu, int node)
+{
+ printk(KERN_INFO "Mapping cpu %d to node %d\n", cpu, node);
+ cpu_set(cpu, node_to_cpumask_map[node]);
+ cpu_to_node_map[cpu] = node;
+}
+
+/* undo a mapping between cpu and node. */
+static void unmap_cpu_to_node(int cpu)
+{
+ int node;
+
+ printk(KERN_INFO "Unmapping cpu %d from all nodes\n", cpu);
+ for (node = 0; node < MAX_NUMNODES; node++)
+ cpu_clear(cpu, node_to_cpumask_map[node]);
+ cpu_to_node_map[cpu] = 0;
+}
+#else /* !(CONFIG_NUMA && CONFIG_X86_32) */
+#define map_cpu_to_node(cpu, node) ({})
+#define unmap_cpu_to_node(cpu) ({})
+#endif
+
+#ifdef CONFIG_X86_32
+u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly =
+ { [0 ... NR_CPUS-1] = BAD_APICID };
+
+void map_cpu_to_logical_apicid(void)
+{
+ int cpu = smp_processor_id();
+ int apicid = logical_smp_processor_id();
+ int node = apicid_to_node(apicid);
+
+ if (!node_online(node))
+ node = first_online_node;
+
+ cpu_2_logical_apicid[cpu] = apicid;
+ map_cpu_to_node(cpu, node);
+}
+
+void unmap_cpu_to_logical_apicid(int cpu)
+{
+ cpu_2_logical_apicid[cpu] = BAD_APICID;
+ unmap_cpu_to_node(cpu);
+}
+#else
+#define unmap_cpu_to_logical_apicid(cpu) do {} while (0)
+#define map_cpu_to_logical_apicid() do {} while (0)
+#endif
+
static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 33758a2..1eb7b73 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -74,7 +74,8 @@ EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);

u8 apicid_2_node[MAX_APICID];

-static void map_cpu_to_logical_apicid(void);
+extern void map_cpu_to_logical_apicid(void);
+extern void unmap_cpu_to_logical_apicid(int cpu);

/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };
@@ -262,62 +263,6 @@ extern struct {
unsigned short ss;
} stack_start;

-#ifdef CONFIG_NUMA
-
-/* which logical CPUs are on which nodes */
-cpumask_t node_to_cpumask_map[MAX_NUMNODES] __read_mostly =
- { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
-EXPORT_SYMBOL(node_to_cpumask_map);
-/* which node each logical CPU is on */
-int cpu_to_node_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
-EXPORT_SYMBOL(cpu_to_node_map);
-
-/* set up a mapping between cpu and node. */
-static inline void map_cpu_to_node(int cpu, int node)
-{
- printk("Mapping cpu %d to node %d\n", cpu, node);
- cpu_set(cpu, node_to_cpumask_map[node]);
- cpu_to_node_map[cpu] = node;
-}
-
-/* undo a mapping between cpu and node. */
-static inline void unmap_cpu_to_node(int cpu)
-{
- int node;
-
- printk("Unmapping cpu %d from all nodes\n", cpu);
- for (node = 0; node < MAX_NUMNODES; node ++)
- cpu_clear(cpu, node_to_cpumask_map[node]);
- cpu_to_node_map[cpu] = 0;
-}
-#else /* !CONFIG_NUMA */
-
-#define map_cpu_to_node(cpu, node) ({})
-#define unmap_cpu_to_node(cpu) ({})
-
-#endif /* CONFIG_NUMA */
-
-u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
-
-static void map_cpu_to_logical_apicid(void)
-{
- int cpu = smp_processor_id();
- int apicid = logical_smp_processor_id();
- int node = apicid_to_node(apicid);
-
- if (!node_online(node))
- node = first_online_node;
-
- cpu_2_logical_apicid[cpu] = apicid;
- map_cpu_to_node(cpu, node);
-}
-
-static void unmap_cpu_to_logical_apicid(int cpu)
-{
- cpu_2_logical_apicid[cpu] = BAD_APICID;
- unmap_cpu_to_node(cpu);
-}
-
static inline void __inquire_remote_apic(int apicid)
{
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
--
1.5.0.6

2008-03-19 20:22:31

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 69/79] [PATCH] get rid of smp_boot_cpus

From: Glauber Costa <[email protected]>

This patch get rid of smp_boot_cpus(), since it does not
boot any cpu anymore. Its code is split in a way to make
it closer to x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 30 +++++++++++-------------------
1 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 14db038..d153d84 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -172,21 +172,19 @@ static int __init smp_sanity_check(unsigned max_cpus)
return 0;
}

-/*
- * Cycle through the processors sending APIC IPIs to boot each.
- */
-static void __init smp_boot_cpus(unsigned int max_cpus)
+/* These are wrappers to interface to the new boot process. Someone
+ who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
+void __init native_smp_prepare_cpus(unsigned int max_cpus)
{
+ nmi_watchdog_default();
+ cpu_callin_map = cpumask_of_cpu(0);
+ mb();
+
/*
* Setup boot CPU information
*/
smp_store_cpu_info(0); /* Final full version of the data */
- printk(KERN_INFO "CPU%d: ", 0);
- print_cpu_info(&cpu_data(0));
-
- boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
boot_cpu_logical_apicid = logical_smp_processor_id();
-
current_thread_info()->cpu = 0;

set_cpu_sibling_map(0);
@@ -197,25 +195,19 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
return;
}

+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
+
connect_bsp_APIC();
setup_local_APIC();
end_local_APIC_setup();
map_cpu_to_logical_apicid();

-
setup_portio_remap();

smpboot_setup_io_apic();

+ printk(KERN_INFO "CPU%d: ", 0);
+ print_cpu_info(&cpu_data(0));
setup_boot_clock();
}

-/* These are wrappers to interface to the new boot process. Someone
- who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
-void __init native_smp_prepare_cpus(unsigned int max_cpus)
-{
- nmi_watchdog_default();
- cpu_callin_map = cpumask_of_cpu(0);
- mb();
- smp_boot_cpus(max_cpus);
-}
--
1.5.0.6

2008-03-19 20:24:09

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 56/79] [PATCH] minor adjustments for do_boot_cpu

From: Glauber Costa <[email protected]>

This patch provides minor adjustments for do_boot_cpus
in both architectures to allow for integration

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 22 ++++++++++++++--------
arch/x86/kernel/smpboot_64.c | 15 ++++++---------
2 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index bd2f886..5165b11 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -556,7 +556,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
* Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu.
*/
{
- unsigned long boot_error;
+ unsigned long boot_error = 0;
int timeout;
unsigned long start_eip;
unsigned short nmi_high = 0, nmi_low = 0;
@@ -566,11 +566,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
};
INIT_WORK(&c_idle.work, do_fork_idle);

- /*
- * Save current MTRR state in case it was changed since early boot
- * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
- */
- mtrr_save_state();
+ alternatives_smp_switch(1);

c_idle.idle = get_idle_for_cpu(cpu);

@@ -607,8 +603,6 @@ do_rest:
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();

- alternatives_smp_switch(1);
-
/* So we see what's up */
printk("Booting processor %d/%d ip %lx\n", cpu, apicid, start_eip);
/* Stack for startup_32 can be just as for start_secondary onwards */
@@ -628,6 +622,12 @@ do_rest:
store_NMI_vector(&nmi_high, &nmi_low);

smpboot_setup_warm_reset_vector(start_eip);
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+

/*
* Starting actual IPI sequence...
@@ -864,6 +864,12 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return -EINVAL;
}

+ /*
+ * Save current MTRR state in case it was changed since early boot
+ * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
+ */
+ mtrr_save_state();
+
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;

__smp_prepare_cpu(cpu);
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index e93fff4..7d1b4cb 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -432,7 +432,7 @@ static void __cpuinit do_fork_idle(struct work_struct *work)
*/
static int __cpuinit do_boot_cpu(int cpu, int apicid)
{
- unsigned long boot_error;
+ unsigned long boot_error = 0;
int timeout;
unsigned long start_rip;
struct create_idle c_idle = {
@@ -531,11 +531,6 @@ do_rest:
apic_read(APIC_ESR);

/*
- * Status is now clean
- */
- boot_error = 0;
-
- /*
* Starting actual IPI sequence...
*/
boot_error = wakeup_secondary_via_INIT(apicid, start_rip);
@@ -564,7 +559,7 @@ do_rest:
print_cpu_info(&cpu_data(cpu));
} else {
boot_error = 1;
- if (*((volatile unsigned char *)phys_to_virt(SMP_TRAMPOLINE_BASE))
+ if (*((volatile unsigned char *)trampoline_base)
== 0xA5)
/* trampoline started but...? */
printk("Stuck ??\n");
@@ -583,10 +578,12 @@ do_rest:
cpu_clear(cpu, cpu_present_map);
cpu_clear(cpu, cpu_possible_map);
per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
- return -EIO;
}

- return 0;
+ /* mark "stuck" area as not stuck */
+ *((volatile unsigned long *)trampoline_base) = 0;
+
+ return boot_error;
}

cycles_t cacheflush_time;
--
1.5.0.6

2008-03-19 20:22:53

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 30/79] [PATCH] fill cpu to apicid and present map in mpparse

From: Glauber Costa <[email protected]>

This is the way x86_64 does, and complement the already
present patch that does the bios cpu to apicid mapping here

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/mpparse_32.c | 19 +++++++++++++++++--
arch/x86/kernel/smpboot_32.c | 24 +++++++-----------------
2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/arch/x86/kernel/mpparse_32.c b/arch/x86/kernel/mpparse_32.c
index 56fb828..b18fb0f 100644
--- a/arch/x86/kernel/mpparse_32.c
+++ b/arch/x86/kernel/mpparse_32.c
@@ -106,7 +106,8 @@ static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __cpuinit

static void __cpuinit MP_processor_info (struct mpc_config_processor *m)
{
- int ver, apicid;
+ int ver, apicid, cpu;
+ cpumask_t tmp_map;
physid_mask_t phys_cpu;

if (!(m->mpc_cpuflag & CPU_ENABLED)) {
@@ -199,6 +200,16 @@ static void __cpuinit MP_processor_info (struct mpc_config_processor *m)

cpu_set(num_processors, cpu_possible_map);
num_processors++;
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+
+ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
+ /*
+ * x86_bios_cpu_apicid is required to have processors listed
+ * in same order as logical cpu numbers. Hence the first
+ * entry is BSP, and so on.
+ */
+ cpu = 0;

/*
* Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
@@ -221,12 +232,16 @@ static void __cpuinit MP_processor_info (struct mpc_config_processor *m)
}
/* are we being called early in kernel startup? */
if (x86_cpu_to_apicid_early_ptr) {
+ u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr;
u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr;
+
+ cpu_to_apicid[cpu] = m->mpc_apicid;
bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
} else {
- int cpu = num_processors - 1;
+ per_cpu(x86_cpu_to_apicid, cpu) = m->mpc_apicid;
per_cpu(x86_bios_cpu_apicid, cpu) = m->mpc_apicid;
}
+ cpu_set(cpu, cpu_present_map);
}

static void __init MP_bus_info (struct mpc_config_bus *m)
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index bf5c9e9..2fea910 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -525,16 +525,6 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
#endif /* WAKE_SECONDARY_VIA_INIT */

extern cpumask_t cpu_initialized;
-static inline int alloc_cpu_id(void)
-{
- cpumask_t tmp_map;
- int cpu;
- cpus_complement(tmp_map, cpu_present_map);
- cpu = first_cpu(tmp_map);
- if (cpu >= NR_CPUS)
- return -ENODEV;
- return cpu;
-}

#ifdef CONFIG_HOTPLUG_CPU
static struct task_struct * __cpuinitdata cpu_idle_tasks[NR_CPUS];
@@ -605,7 +595,6 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)

irq_ctx_init(cpu);

- per_cpu(x86_cpu_to_apicid, cpu) = apicid;
/*
* This grunge runs the startup process for
* the targeted processor.
@@ -666,10 +655,8 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
cpu_clear(cpu, cpu_possible_map);
+ per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
cpucount--;
- } else {
- per_cpu(x86_cpu_to_apicid, cpu) = apicid;
- cpu_set(cpu, cpu_present_map);
}

/* mark "stuck" area as not stuck */
@@ -745,6 +732,7 @@ EXPORT_SYMBOL(xquad_portio);
static void __init disable_smp(void)
{
cpu_possible_map = cpumask_of_cpu(0);
+ cpu_present_map = cpumask_of_cpu(0);
smpboot_clear_io_apic_irqs();
phys_cpu_present_map = physid_mask_of_physid(0);
map_cpu_to_logical_apicid();
@@ -825,7 +813,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
boot_cpu_logical_apicid = logical_smp_processor_id();
- per_cpu(x86_cpu_to_apicid, 0) = boot_cpu_physical_apicid;

current_thread_info()->cpu = 0;

@@ -866,8 +853,11 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
continue;
if (max_cpus <= cpucount+1)
continue;
-
- if (((cpu = alloc_cpu_id()) <= 0) || do_boot_cpu(apicid, cpu))
+ /* Utterly temporary */
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ if (per_cpu(x86_cpu_to_apicid, cpu) == apicid)
+ break;
+ if (do_boot_cpu(apicid, cpu))
printk("CPU #%d not responding - cannot use it.\n",
apicid);
else
--
1.5.0.6

2008-03-19 20:25:53

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 10/79] [PATCH] merge smp_store_cpu_info

From: Glauber Costa <[email protected]>

now that it is the same between arches, put it into smpboot.c

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 77 ++++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 71 +--------------------------------------
arch/x86/kernel/smpboot_64.c | 15 --------
include/asm-x86/smp.h | 2 +
include/asm-x86/smp_32.h | 2 -
5 files changed, 80 insertions(+), 87 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index b13b9d5..a157a52 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -45,6 +45,83 @@ unsigned char *trampoline_base = __va(SMP_TRAMPOLINE_BASE);
/* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map;

+#ifdef CONFIG_X86_32
+/* Set if we find a B stepping CPU */
+int __cpuinitdata smp_b_stepping;
+#endif
+
+static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_32
+ /*
+ * Mask B, Pentium, but not Pentium MMX
+ */
+ if (c->x86_vendor == X86_VENDOR_INTEL &&
+ c->x86 == 5 &&
+ c->x86_mask >= 1 && c->x86_mask <= 4 &&
+ c->x86_model <= 3)
+ /*
+ * Remember we have B step Pentia with bugs
+ */
+ smp_b_stepping = 1;
+
+ /*
+ * Certain Athlons might work (for various values of 'work') in SMP
+ * but they are not certified as MP capable.
+ */
+ if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
+
+ if (num_possible_cpus() == 1)
+ goto valid_k7;
+
+ /* Athlon 660/661 is valid. */
+ if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
+ (c->x86_mask == 1)))
+ goto valid_k7;
+
+ /* Duron 670 is valid */
+ if ((c->x86_model == 7) && (c->x86_mask == 0))
+ goto valid_k7;
+
+ /*
+ * Athlon 662, Duron 671, and Athlon >model 7 have capability
+ * bit. It's worth noting that the A5 stepping (662) of some
+ * Athlon XP's have the MP bit set.
+ * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for
+ * more.
+ */
+ if (((c->x86_model == 6) && (c->x86_mask >= 2)) ||
+ ((c->x86_model == 7) && (c->x86_mask >= 1)) ||
+ (c->x86_model > 7))
+ if (cpu_has_mp)
+ goto valid_k7;
+
+ /* If we get here, not a certified SMP capable AMD system. */
+ add_taint(TAINT_UNSAFE_SMP);
+ }
+
+valid_k7:
+ ;
+#endif
+}
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+
+void __cpuinit smp_store_cpu_info(int id)
+{
+ struct cpuinfo_x86 *c = &cpu_data(id);
+
+ *c = boot_cpu_data;
+ c->cpu_index = id;
+ if (id != 0)
+ identify_secondary_cpu(c);
+ smp_apply_quirks(c);
+}
+
+
void __cpuinit set_cpu_sibling_map(int cpu)
{
int i;
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index e050064..0bfb31e 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -59,8 +59,7 @@
#include <asm/vmi.h>
#include <asm/mtrr.h>

-/* Set if we find a B stepping CPU */
-static int __cpuinitdata smp_b_stepping;
+extern int smp_b_stepping;

static cpumask_t smp_commenced_mask;

@@ -78,74 +77,6 @@ static void map_cpu_to_logical_apicid(void);
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

-static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
-{
- /*
- * Mask B, Pentium, but not Pentium MMX
- */
- if (c->x86_vendor == X86_VENDOR_INTEL &&
- c->x86 == 5 &&
- c->x86_mask >= 1 && c->x86_mask <= 4 &&
- c->x86_model <= 3)
- /*
- * Remember we have B step Pentia with bugs
- */
- smp_b_stepping = 1;
-
- /*
- * Certain Athlons might work (for various values of 'work') in SMP
- * but they are not certified as MP capable.
- */
- if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
-
- if (num_possible_cpus() == 1)
- goto valid_k7;
-
- /* Athlon 660/661 is valid. */
- if ((c->x86_model==6) && ((c->x86_mask==0) || (c->x86_mask==1)))
- goto valid_k7;
-
- /* Duron 670 is valid */
- if ((c->x86_model==7) && (c->x86_mask==0))
- goto valid_k7;
-
- /*
- * Athlon 662, Duron 671, and Athlon >model 7 have capability bit.
- * It's worth noting that the A5 stepping (662) of some Athlon XP's
- * have the MP bit set.
- * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for more.
- */
- if (((c->x86_model==6) && (c->x86_mask>=2)) ||
- ((c->x86_model==7) && (c->x86_mask>=1)) ||
- (c->x86_model> 7))
- if (cpu_has_mp)
- goto valid_k7;
-
- /* If we get here, it's not a certified SMP capable AMD system. */
- add_taint(TAINT_UNSAFE_SMP);
- }
-
-valid_k7:
- ;
-
-}
-
-/*
- * The bootstrap kernel entry code has set these up. Save them for
- * a given CPU
- */
-
-void __cpuinit smp_store_cpu_info(int id)
-{
- struct cpuinfo_x86 *c = &cpu_data(id);
-
- *c = boot_cpu_data;
- c->cpu_index = id;
- if (id != 0)
- identify_secondary_cpu(c);
- smp_apply_quirks(c);
-}
-
static atomic_t init_deasserted;

static void __cpuinit smp_callin(void)
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index f84e30d..c213345 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -85,21 +85,6 @@ struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p))
#endif

-/*
- * The bootstrap kernel entry code has set these up. Save them for
- * a given CPU
- */
-
-static void __cpuinit smp_store_cpu_info(int id)
-{
- struct cpuinfo_x86 *c = &cpu_data(id);
-
- *c = boot_cpu_data;
- c->cpu_index = id;
- if (id != 0)
- identify_secondary_cpu(c);
-}
-
static inline void wait_for_init_deassert(atomic_t *deassert)
{
while (!atomic_read(deassert))
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 4dc271b..b4c5143 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -88,6 +88,8 @@ extern void prefill_possible_map(void);

#define SMP_TRAMPOLINE_BASE 0x6000
extern unsigned long setup_trampoline(void);
+
+void smp_store_cpu_info(int id);
#endif

#ifdef CONFIG_X86_32
diff --git a/include/asm-x86/smp_32.h b/include/asm-x86/smp_32.h
index 76740de..51624ab 100644
--- a/include/asm-x86/smp_32.h
+++ b/include/asm-x86/smp_32.h
@@ -42,8 +42,6 @@ DECLARE_PER_CPU(int, cpu_number);

extern int safe_smp_processor_id(void);

-void __cpuinit smp_store_cpu_info(int id);
-
/* We don't mark CPUs online until __cpu_up(), so we need another measure */
static inline int num_booting_cpus(void)
{
--
1.5.0.6

2008-03-19 20:26:45

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 65/79] [PATCH] integrate start_secondary

From: Glauber Costa <[email protected]>

It now looks the same between architectures, so we
merge it in smpboot.c. Minor differences goes inside
an ifdef

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 86 +++++++++++++++++++++++++++++++++++++++++-
arch/x86/kernel/smpboot_32.c | 75 ------------------------------------
arch/x86/kernel/smpboot_64.c | 63 ------------------------------
3 files changed, 85 insertions(+), 139 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 69c1796..a36ae27 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -17,6 +17,7 @@
#include <asm/tlbflush.h>
#include <asm/mtrr.h>
#include <asm/nmi.h>
+#include <asm/vmi.h>
#include <linux/mc146818rtc.h>

#include <mach_apic.h>
@@ -229,6 +230,90 @@ void __cpuinit smp_callin(void)
cpu_set(cpuid, cpu_callin_map);
}

+/*
+ * Activate a secondary processor.
+ */
+void __cpuinit start_secondary(void *unused)
+{
+ /*
+ * Don't put *anything* before cpu_init(), SMP booting is too
+ * fragile that we want to limit the things done here to the
+ * most necessary things.
+ */
+#ifdef CONFIG_VMI
+ vmi_bringup();
+#endif
+ cpu_init();
+ preempt_disable();
+ smp_callin();
+
+ /* otherwise gcc will move up smp_processor_id before the cpu_init */
+ barrier();
+ /*
+ * Check TSC synchronization with the BP:
+ */
+ check_tsc_sync_target();
+
+ if (nmi_watchdog == NMI_IO_APIC) {
+ disable_8259A_irq(0);
+ enable_NMI_through_LVT0();
+ enable_8259A_irq(0);
+ }
+
+ /* This must be done before setting cpu_online_map */
+ set_cpu_sibling_map(raw_smp_processor_id());
+ wmb();
+
+ /*
+ * We need to hold call_lock, so there is no inconsistency
+ * between the time smp_call_function() determines number of
+ * IPI recipients, and the time when the determination is made
+ * for which cpus receive the IPI. Holding this
+ * lock helps us to not include this cpu in a currently in progress
+ * smp_call_function().
+ */
+ lock_ipi_call_lock();
+#ifdef CONFIG_X86_64
+ spin_lock(&vector_lock);
+
+ /* Setup the per cpu irq handling data structures */
+ __setup_vector_irq(smp_processor_id());
+ /*
+ * Allow the master to continue.
+ */
+ spin_unlock(&vector_lock);
+#endif
+ cpu_set(smp_processor_id(), cpu_online_map);
+ unlock_ipi_call_lock();
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+
+ setup_secondary_clock();
+
+ wmb();
+ cpu_idle();
+}
+
+#ifdef CONFIG_X86_32
+/*
+ * Everything has been set up for the secondary
+ * CPUs - they just need to reload everything
+ * from the task structure
+ * This function must not return.
+ */
+void __devinit initialize_secondary(void)
+{
+ /*
+ * We don't actually need to load the full TSS,
+ * basically just the stack pointer and the ip.
+ */
+
+ asm volatile(
+ "movl %0,%%esp\n\t"
+ "jmp *%1"
+ :
+ :"m" (current->thread.sp), "m" (current->thread.ip));
+}
+#endif

static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
{
@@ -533,7 +618,6 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
}
#endif /* WAKE_SECONDARY_VIA_NMI */

-extern void start_secondary(void *unused);
#ifdef WAKE_SECONDARY_VIA_INIT
static int __devinit
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index e82eeb2..77b045c 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -80,81 +80,6 @@ extern void unmap_cpu_to_logical_apicid(int cpu);
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

-extern void smp_callin(void);
-
-/*
- * Activate a secondary processor.
- */
-void __cpuinit start_secondary(void *unused)
-{
- /*
- * Don't put *anything* before cpu_init(), SMP booting is too
- * fragile that we want to limit the things done here to the
- * most necessary things.
- */
-#ifdef CONFIG_VMI
- vmi_bringup();
-#endif
- cpu_init();
- preempt_disable();
- smp_callin();
-
- /* otherwise gcc will move up smp_processor_id before the cpu_init */
- barrier();
- /*
- * Check TSC synchronization with the BP:
- */
- check_tsc_sync_target();
-
- if (nmi_watchdog == NMI_IO_APIC) {
- disable_8259A_irq(0);
- enable_NMI_through_LVT0();
- enable_8259A_irq(0);
- }
-
- /* This must be done before setting cpu_online_map */
- set_cpu_sibling_map(raw_smp_processor_id());
- wmb();
-
- /*
- * We need to hold call_lock, so there is no inconsistency
- * between the time smp_call_function() determines number of
- * IPI recipients, and the time when the determination is made
- * for which cpus receive the IPI. Holding this
- * lock helps us to not include this cpu in a currently in progress
- * smp_call_function().
- */
- lock_ipi_call_lock();
- cpu_set(smp_processor_id(), cpu_online_map);
- unlock_ipi_call_lock();
- per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
-
- setup_secondary_clock();
-
- wmb();
- cpu_idle();
-}
-
-/*
- * Everything has been set up for the secondary
- * CPUs - they just need to reload everything
- * from the task structure
- * This function must not return.
- */
-void __devinit initialize_secondary(void)
-{
- /*
- * We don't actually need to load the full TSS,
- * basically just the stack pointer and the ip.
- */
-
- asm volatile(
- "movl %0,%%esp\n\t"
- "jmp *%1"
- :
- :"m" (current->thread.sp),"m" (current->thread.ip));
-}
-
#ifdef CONFIG_HOTPLUG_CPU
void cpu_exit_clear(void)
{
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 71f13b1..60cd8cf 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -71,69 +71,6 @@ int smp_threads_ready;
/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

-extern void smp_callin(void);
-/*
- * Setup code on secondary processor (after comming out of the trampoline)
- */
-void __cpuinit start_secondary(void)
-{
- /*
- * Dont put anything before smp_callin(), SMP
- * booting is too fragile that we want to limit the
- * things done here to the most necessary things.
- */
- cpu_init();
- preempt_disable();
- smp_callin();
-
- /* otherwise gcc will move up the smp_processor_id before the cpu_init */
- barrier();
-
- /*
- * Check TSC sync first:
- */
- check_tsc_sync_target();
-
- if (nmi_watchdog == NMI_IO_APIC) {
- disable_8259A_irq(0);
- enable_NMI_through_LVT0();
- enable_8259A_irq(0);
- }
-
- /*
- * The sibling maps must be set before turing the online map on for
- * this cpu
- */
- set_cpu_sibling_map(smp_processor_id());
-
- /*
- * We need to hold call_lock, so there is no inconsistency
- * between the time smp_call_function() determines number of
- * IPI recipients, and the time when the determination is made
- * for which cpus receive the IPI in genapic_flat.c. Holding this
- * lock helps us to not include this cpu in a currently in progress
- * smp_call_function().
- */
- lock_ipi_call_lock();
- spin_lock(&vector_lock);
-
- /* Setup the per cpu irq handling data structures */
- __setup_vector_irq(smp_processor_id());
- /*
- * Allow the master to continue.
- */
- spin_unlock(&vector_lock);
- cpu_set(smp_processor_id(), cpu_online_map);
- unlock_ipi_call_lock();
-
- per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
-
- setup_secondary_clock();
-
- wmb();
- cpu_idle();
-}
-
cycles_t cacheflush_time;
unsigned long cache_decay_ticks;

--
1.5.0.6

2008-03-19 20:25:21

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 50/79] [PATCH] use create_idle struct in do_boot_cpu

From: Glauber Costa <[email protected]>

Use a new worker, with help of the create_idle struct
to fork the idle thread. We now have two workers, the first
of them triggered by __smp_prepare_cpu. But the later is
going away soon.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 86 ++++++++++++++++++++++++++++-------------
1 files changed, 59 insertions(+), 27 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index c30abed..fc1eb52 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -79,6 +79,24 @@ static void map_cpu_to_logical_apicid(void);
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

+/* Store all idle threads, this can be reused instead of creating
+* a new thread. Also avoids complicated thread destroy functionality
+* for idle threads.
+*/
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Needed only for CONFIG_HOTPLUG_CPU because __cpuinitdata is
+ * removed after init for !CONFIG_HOTPLUG_CPU.
+ */
+static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
+#define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x))
+#define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p))
+#else
+struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
+#define get_idle_for_cpu(x) (idle_thread_array[(x)])
+#define set_idle_for_cpu(x, p) (idle_thread_array[(x)] = (p))
+#endif
+
static atomic_t init_deasserted;

static void __cpuinit smp_callin(void)
@@ -513,30 +531,21 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)

extern cpumask_t cpu_initialized;

-#ifdef CONFIG_HOTPLUG_CPU
-static struct task_struct * __cpuinitdata cpu_idle_tasks[NR_CPUS];
-static inline struct task_struct * __cpuinit alloc_idle_task(int cpu)
-{
+struct create_idle {
+ struct work_struct work;
struct task_struct *idle;
+ struct completion done;
+ int cpu;
+};

- if ((idle = cpu_idle_tasks[cpu]) != NULL) {
- /* initialize thread_struct. we really want to avoid destroy
- * idle tread
- */
- idle->thread.sp = (unsigned long)task_pt_regs(idle);
- init_idle(idle, cpu);
- return idle;
- }
- idle = fork_idle(cpu);
+static void __cpuinit do_fork_idle(struct work_struct *work)
+{
+ struct create_idle *c_idle =
+ container_of(work, struct create_idle, work);

- if (!IS_ERR(idle))
- cpu_idle_tasks[cpu] = idle;
- return idle;
+ c_idle->idle = fork_idle(c_idle->cpu);
+ complete(&c_idle->done);
}
-#else
-#define alloc_idle_task(cpu) fork_idle(cpu)
-#endif
-
static int __cpuinit do_boot_cpu(int apicid, int cpu)
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -544,11 +553,15 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
* Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu.
*/
{
- struct task_struct *idle;
unsigned long boot_error;
int timeout;
unsigned long start_eip;
unsigned short nmi_high = 0, nmi_low = 0;
+ struct create_idle c_idle = {
+ .cpu = cpu,
+ .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
+ };
+ INIT_WORK(&c_idle.work, do_fork_idle);

/*
* Save current MTRR state in case it was changed since early boot
@@ -556,19 +569,38 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
*/
mtrr_save_state();

+ c_idle.idle = get_idle_for_cpu(cpu);
+
/*
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
- idle = alloc_idle_task(cpu);
- if (IS_ERR(idle))
- panic("failed fork for CPU %d", cpu);
+ if (c_idle.idle) {
+ c_idle.idle->thread.sp = (unsigned long) (((struct pt_regs *)
+ (THREAD_SIZE + task_stack_page(c_idle.idle))) - 1);
+ init_idle(c_idle.idle, cpu);
+ goto do_rest;
+ }
+
+ if (!keventd_up() || current_is_keventd())
+ c_idle.work.func(&c_idle.work);
+ else {
+ schedule_work(&c_idle.work);
+ wait_for_completion(&c_idle.done);
+ }
+
+ if (IS_ERR(c_idle.idle)) {
+ printk(KERN_ERR "failed fork for CPU %d\n", cpu);
+ return PTR_ERR(c_idle.idle);
+ }

+ set_idle_for_cpu(cpu, c_idle.idle);
+do_rest:
+ per_cpu(current_task, cpu) = c_idle.idle;
init_gdt(cpu);
- per_cpu(current_task, cpu) = idle;
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);

- idle->thread.ip = (unsigned long) start_secondary;
+ c_idle.idle->thread.ip = (unsigned long) start_secondary;
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();

@@ -577,7 +609,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
/* So we see what's up */
printk("Booting processor %d/%d ip %lx\n", cpu, apicid, start_eip);
/* Stack for startup_32 can be just as for start_secondary onwards */
- stack_start.sp = (void *) idle->thread.sp;
+ stack_start.sp = (void *) c_idle.idle->thread.sp;

irq_ctx_init(cpu);

--
1.5.0.6

2008-03-19 20:30:01

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 79/79] [PATCH] remove smpboot_32.c and smpboot_64.c

From: Glauber Costa <[email protected]>

Remove the last leftovers from the files. Move the ones
that are still used to the files they belong, the others
that grep can't reach, simply throw away.

Merge comments ontop of file and that's it: smpboot integrated

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/Makefile | 4 +-
arch/x86/kernel/smpboot.c | 42 ++++++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 68 ---------------------------------------
arch/x86/kernel/smpboot_64.c | 73 ------------------------------------------
arch/x86/pci/numa.c | 7 +++-
5 files changed, 50 insertions(+), 144 deletions(-)
delete mode 100644 arch/x86/kernel/smpboot_32.c
delete mode 100644 arch/x86/kernel/smpboot_64.c

diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index dc333c8..c3adadd 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -47,10 +47,10 @@ obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_PCI) += early-quirks.o
apm-y := apm_32.o
obj-$(CONFIG_APM) += apm.o
-obj-$(CONFIG_X86_SMP) += smpboot_$(BITS).o smp.o
+obj-$(CONFIG_X86_SMP) += smp.o
obj-$(CONFIG_X86_SMP) += smpboot.o tsc_sync.o ipi.o tlb_$(BITS).o
obj-$(CONFIG_X86_32_SMP) += smpcommon.o
-obj-$(CONFIG_X86_64_SMP) += smpboot_64.o tsc_sync.o smpcommon.o
+obj-$(CONFIG_X86_64_SMP) += tsc_sync.o smpcommon.o
obj-$(CONFIG_X86_TRAMPOLINE) += trampoline_$(BITS).o
obj-$(CONFIG_X86_MPPARSE) += mpparse_$(BITS).o
obj-$(CONFIG_X86_LOCAL_APIC) += apic_$(BITS).o nmi_$(BITS).o
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 75637fb..61b9a5b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1,3 +1,44 @@
+/*
+ * x86 SMP booting functions
+ *
+ * (c) 1995 Alan Cox, Building #3 <[email protected]>
+ * (c) 1998, 1999, 2000 Ingo Molnar <[email protected]>
+ * Copyright 2001 Andi Kleen, SuSE Labs.
+ *
+ * Much of the core SMP work is based on previous work by Thomas Radke, to
+ * whom a great many thanks are extended.
+ *
+ * Thanks to Intel for making available several different Pentium,
+ * Pentium Pro and Pentium-II/Xeon MP machines.
+ * Original development of Linux SMP code supported by Caldera.
+ *
+ * This code is released under the GNU General Public License version 2 or
+ * later.
+ *
+ * Fixes
+ * Felix Koop : NR_CPUS used properly
+ * Jose Renau : Handle single CPU case.
+ * Alan Cox : By repeated request 8) - Total BogoMIPS report.
+ * Greg Wright : Fix for kernel stacks panic.
+ * Erich Boleyn : MP v1.4 and additional changes.
+ * Matthias Sattler : Changes for 2.1 kernel map.
+ * Michel Lespinasse : Changes for 2.1 kernel map.
+ * Michael Chastain : Change trampoline.S to gnu as.
+ * Alan Cox : Dumb bug: 'B' step PPro's are fine
+ * Ingo Molnar : Added APIC timers, based on code
+ * from Jose Renau
+ * Ingo Molnar : various cleanups and rewrites
+ * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
+ * Maciej W. Rozycki : Bits for genuine 82489DX APICs
+ * Andi Kleen : Changed for SMP boot into long mode.
+ * Martin J. Bligh : Added support for multi-quad systems
+ * Dave Jones : Report invalid combinations of Athlon CPUs.
+ * Rusty Russell : Hacked into shape for new "hotplug" boot process.
+ * Andi Kleen : Converted to new state machine.
+ * Ashok Raj : CPU hotplug support
+ * Glauber Costa : i386 and x86_64 integration
+ */
+
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/module.h>
@@ -44,6 +85,7 @@ u16 x86_bios_cpu_apicid_init[NR_CPUS] __initdata
void *x86_bios_cpu_apicid_early_ptr;
DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
+u8 apicid_2_node[MAX_APICID];
#endif

/* State of each CPU */
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
deleted file mode 100644
index 3590afe..0000000
--- a/arch/x86/kernel/smpboot_32.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * x86 SMP booting functions
- *
- * (c) 1995 Alan Cox, Building #3 <[email protected]>
- * (c) 1998, 1999, 2000 Ingo Molnar <[email protected]>
- *
- * Much of the core SMP work is based on previous work by Thomas Radke, to
- * whom a great many thanks are extended.
- *
- * Thanks to Intel for making available several different Pentium,
- * Pentium Pro and Pentium-II/Xeon MP machines.
- * Original development of Linux SMP code supported by Caldera.
- *
- * This code is released under the GNU General Public License version 2 or
- * later.
- *
- * Fixes
- * Felix Koop : NR_CPUS used properly
- * Jose Renau : Handle single CPU case.
- * Alan Cox : By repeated request 8) - Total BogoMIPS report.
- * Greg Wright : Fix for kernel stacks panic.
- * Erich Boleyn : MP v1.4 and additional changes.
- * Matthias Sattler : Changes for 2.1 kernel map.
- * Michel Lespinasse : Changes for 2.1 kernel map.
- * Michael Chastain : Change trampoline.S to gnu as.
- * Alan Cox : Dumb bug: 'B' step PPro's are fine
- * Ingo Molnar : Added APIC timers, based on code
- * from Jose Renau
- * Ingo Molnar : various cleanups and rewrites
- * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
- * Maciej W. Rozycki : Bits for genuine 82489DX APICs
- * Martin J. Bligh : Added support for multi-quad systems
- * Dave Jones : Report invalid combinations of Athlon CPUs.
-* Rusty Russell : Hacked into shape for new "hotplug" boot process. */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/bootmem.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <linux/percpu.h>
-#include <linux/nmi.h>
-
-#include <linux/delay.h>
-#include <linux/mc146818rtc.h>
-#include <asm/tlbflush.h>
-#include <asm/desc.h>
-#include <asm/arch_hooks.h>
-#include <asm/nmi.h>
-
-#include <mach_apic.h>
-#include <mach_wakecpu.h>
-#include <smpboot_hooks.h>
-#include <asm/vmi.h>
-#include <asm/mtrr.h>
-
-u8 apicid_2_node[MAX_APICID];
-
-/* Where the IO area was mapped on multiquad, always 0 otherwise */
-void *xquad_portio;
-#ifdef CONFIG_X86_NUMAQ
-EXPORT_SYMBOL(xquad_portio);
-#endif
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
deleted file mode 100644
index 66b5562..0000000
--- a/arch/x86/kernel/smpboot_64.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * x86 SMP booting functions
- *
- * (c) 1995 Alan Cox, Building #3 <[email protected]>
- * (c) 1998, 1999, 2000 Ingo Molnar <[email protected]>
- * Copyright 2001 Andi Kleen, SuSE Labs.
- *
- * Much of the core SMP work is based on previous work by Thomas Radke, to
- * whom a great many thanks are extended.
- *
- * Thanks to Intel for making available several different Pentium,
- * Pentium Pro and Pentium-II/Xeon MP machines.
- * Original development of Linux SMP code supported by Caldera.
- *
- * This code is released under the GNU General Public License version 2
- *
- * Fixes
- * Felix Koop : NR_CPUS used properly
- * Jose Renau : Handle single CPU case.
- * Alan Cox : By repeated request 8) - Total BogoMIP report.
- * Greg Wright : Fix for kernel stacks panic.
- * Erich Boleyn : MP v1.4 and additional changes.
- * Matthias Sattler : Changes for 2.1 kernel map.
- * Michel Lespinasse : Changes for 2.1 kernel map.
- * Michael Chastain : Change trampoline.S to gnu as.
- * Alan Cox : Dumb bug: 'B' step PPro's are fine
- * Ingo Molnar : Added APIC timers, based on code
- * from Jose Renau
- * Ingo Molnar : various cleanups and rewrites
- * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
- * Maciej W. Rozycki : Bits for genuine 82489DX APICs
- * Andi Kleen : Changed for SMP boot into long mode.
- * Rusty Russell : Hacked into shape for new "hotplug" boot process.
- * Andi Kleen : Converted to new state machine.
- * Various cleanups.
- * Probably mostly hotplug CPU ready now.
- * Ashok Raj : CPU hotplug support
- */
-
-
-#include <linux/init.h>
-
-#include <linux/mm.h>
-#include <linux/kernel_stat.h>
-#include <linux/bootmem.h>
-#include <linux/thread_info.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mc146818rtc.h>
-#include <linux/smp.h>
-#include <linux/kdebug.h>
-
-#include <asm/acpi.h>
-#include <asm/mtrr.h>
-#include <asm/pgalloc.h>
-#include <asm/desc.h>
-#include <asm/tlbflush.h>
-#include <asm/proto.h>
-#include <asm/nmi.h>
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/numa.h>
-
-#include <mach_wakecpu.h>
-#include <mach_apic.h>
-#include <smpboot_hooks.h>
-#include <mach_apic.h>
-
-/* Set when the idlers are all forked */
-int smp_threads_ready;
-
-cycles_t cacheflush_time;
-unsigned long cache_decay_ticks;
diff --git a/arch/x86/pci/numa.c b/arch/x86/pci/numa.c
index 9e30378..79d0a98 100644
--- a/arch/x86/pci/numa.c
+++ b/arch/x86/pci/numa.c
@@ -20,7 +20,12 @@ int mp_bus_id_to_local[MAX_MP_BUSSES];
int quad_local_to_mp_bus_id [NR_CPUS/4][4];
#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])

-extern void *xquad_portio; /* Where the IO area was mapped */
+/* Where the IO area was mapped on multiquad, always 0 otherwise */
+void *xquad_portio;
+#ifdef CONFIG_X86_NUMAQ
+EXPORT_SYMBOL(xquad_portio);
+#endif
+
#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)

#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
--
1.5.0.6

2008-03-19 20:30:36

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 46/79] [PATCH] schedule work only if keventd is already running

From: Glauber Costa <[email protected]>

Only call schedule_work if keventd is already running.
This is already the way x86_64 does

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot_32.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5cae17f..255c6f7 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -708,8 +708,12 @@ static void __cpuinit __smp_prepare_cpu(int cpu)
clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
flush_tlb_all();
- schedule_work(&info.task);
- wait_for_completion(&done);
+ if (!keventd_up() || current_is_keventd())
+ info.task.func(&info.task);
+ else {
+ schedule_work(&info.task);
+ wait_for_completion(&done);
+ }

zap_low_mappings();
}
--
1.5.0.6

2008-03-19 20:31:09

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 28/79] [PATCH] use specialized routine for setup per-cpu area

From: Glauber Costa <[email protected]>

We use the same routing as x86_64, moved now to setup.c.
Just with a few ifdefs inside.
Note that this routing uses prefill_possible_map().
It has the very nice side effect of allowing hotplugging of
cpus that are marked as present but disabled by acpi bios.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/Kconfig | 2 +-
arch/x86/kernel/Makefile | 2 +-
arch/x86/kernel/setup.c | 103 ++++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/setup64.c | 77 -------------------------------
arch/x86/kernel/smpboot_32.c | 2 +
5 files changed, 107 insertions(+), 79 deletions(-)
create mode 100644 arch/x86/kernel/setup.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index a234ce9..5f1f381 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -121,7 +121,7 @@ config ARCH_HAS_CPU_RELAX
def_bool y

config HAVE_SETUP_PER_CPU_AREA
- def_bool X86_64
+ def_bool X86_64 || (X86_SMP && !X86_VOYAGER)

config ARCH_HIBERNATION_POSSIBLE
def_bool y
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 09b7b4e..dc333c8 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -19,7 +19,7 @@ CFLAGS_paravirt.o := $(nostackp)
obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
obj-y += traps_$(BITS).o irq_$(BITS).o
obj-y += time_$(BITS).o ioport.o ldt.o
-obj-y += setup_$(BITS).o i8259_$(BITS).o
+obj-y += setup_$(BITS).o i8259_$(BITS).o setup.o
obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o setup64.o
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
new file mode 100644
index 0000000..1179aa0
--- /dev/null
+++ b/arch/x86/kernel/setup.c
@@ -0,0 +1,103 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/percpu.h>
+#include <asm/smp.h>
+#include <asm/percpu.h>
+#include <asm/sections.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/topology.h>
+
+#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA
+/*
+ * Copy data used in early init routines from the initial arrays to the
+ * per cpu data areas. These arrays then become expendable and the
+ * *_early_ptr's are zeroed indicating that the static arrays are gone.
+ */
+static void __init setup_per_cpu_maps(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+#ifdef CONFIG_SMP
+ if (per_cpu_offset(cpu)) {
+#endif
+ per_cpu(x86_cpu_to_apicid, cpu) =
+ x86_cpu_to_apicid_init[cpu];
+ per_cpu(x86_bios_cpu_apicid, cpu) =
+ x86_bios_cpu_apicid_init[cpu];
+#ifdef CONFIG_NUMA
+ per_cpu(x86_cpu_to_node_map, cpu) =
+ x86_cpu_to_node_map_init[cpu];
+#endif
+#ifdef CONFIG_SMP
+ } else
+ printk(KERN_NOTICE "per_cpu_offset zero for cpu %d\n",
+ cpu);
+#endif
+ }
+
+ /* indicate the early static arrays will soon be gone */
+ x86_cpu_to_apicid_early_ptr = NULL;
+ x86_bios_cpu_apicid_early_ptr = NULL;
+#ifdef CONFIG_NUMA
+ x86_cpu_to_node_map_early_ptr = NULL;
+#endif
+}
+
+#ifdef CONFIG_X86_32
+/*
+ * Great future not-so-futuristic plan: make i386 and x86_64 do it
+ * the same way
+ */
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+#endif
+
+/*
+ * Great future plan:
+ * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
+ * Always point %gs to its beginning
+ */
+void __init setup_per_cpu_areas(void)
+{
+ int i;
+ unsigned long size;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ prefill_possible_map();
+#endif
+
+ /* Copy section for each CPU (we discard the original) */
+ size = PERCPU_ENOUGH_ROOM;
+
+ printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n",
+ size);
+ for_each_cpu_mask(i, cpu_possible_map) {
+ char *ptr;
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+ ptr = alloc_bootmem_pages(size);
+#else
+ int node = early_cpu_to_node(i);
+ if (!node_online(node) || !NODE_DATA(node))
+ ptr = alloc_bootmem_pages(size);
+ else
+ ptr = alloc_bootmem_pages_node(NODE_DATA(node), size);
+#endif
+ if (!ptr)
+ panic("Cannot allocate cpu data for CPU %d\n", i);
+#ifdef CONFIG_X86_64
+ cpu_pda(i)->data_offset = ptr - __per_cpu_start;
+#else
+ __per_cpu_offset[i] = ptr - __per_cpu_start;
+#endif
+ memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+ }
+
+ /* setup percpu data maps early */
+ setup_per_cpu_maps();
+}
+
+#endif
diff --git a/arch/x86/kernel/setup64.c b/arch/x86/kernel/setup64.c
index 143aa78..d4e4281 100644
--- a/arch/x86/kernel/setup64.c
+++ b/arch/x86/kernel/setup64.c
@@ -86,83 +86,6 @@ static int __init nonx32_setup(char *str)
}
__setup("noexec32=", nonx32_setup);

-/*
- * Copy data used in early init routines from the initial arrays to the
- * per cpu data areas. These arrays then become expendable and the
- * *_early_ptr's are zeroed indicating that the static arrays are gone.
- */
-static void __init setup_per_cpu_maps(void)
-{
- int cpu;
-
- for_each_possible_cpu(cpu) {
-#ifdef CONFIG_SMP
- if (per_cpu_offset(cpu)) {
-#endif
- per_cpu(x86_cpu_to_apicid, cpu) =
- x86_cpu_to_apicid_init[cpu];
- per_cpu(x86_bios_cpu_apicid, cpu) =
- x86_bios_cpu_apicid_init[cpu];
-#ifdef CONFIG_NUMA
- per_cpu(x86_cpu_to_node_map, cpu) =
- x86_cpu_to_node_map_init[cpu];
-#endif
-#ifdef CONFIG_SMP
- }
- else
- printk(KERN_NOTICE "per_cpu_offset zero for cpu %d\n",
- cpu);
-#endif
- }
-
- /* indicate the early static arrays will soon be gone */
- x86_cpu_to_apicid_early_ptr = NULL;
- x86_bios_cpu_apicid_early_ptr = NULL;
-#ifdef CONFIG_NUMA
- x86_cpu_to_node_map_early_ptr = NULL;
-#endif
-}
-
-/*
- * Great future plan:
- * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
- * Always point %gs to its beginning
- */
-void __init setup_per_cpu_areas(void)
-{
- int i;
- unsigned long size;
-
-#ifdef CONFIG_HOTPLUG_CPU
- prefill_possible_map();
-#endif
-
- /* Copy section for each CPU (we discard the original) */
- size = PERCPU_ENOUGH_ROOM;
-
- printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", size);
- for_each_cpu_mask (i, cpu_possible_map) {
- char *ptr;
-#ifndef CONFIG_NEED_MULTIPLE_NODES
- ptr = alloc_bootmem_pages(size);
-#else
- int node = early_cpu_to_node(i);
-
- if (!node_online(node) || !NODE_DATA(node))
- ptr = alloc_bootmem_pages(size);
- else
- ptr = alloc_bootmem_pages_node(NODE_DATA(node), size);
-#endif
- if (!ptr)
- panic("Cannot allocate cpu data for CPU %d\n", i);
- cpu_pda(i)->data_offset = ptr - __per_cpu_start;
- memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
- }
-
- /* setup percpu data maps early */
- setup_per_cpu_maps();
-}
-
void pda_init(int cpu)
{
struct x8664_pda *pda = cpu_pda(cpu);
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 92a5df6..bf5c9e9 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -665,6 +665,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
unmap_cpu_to_logical_apicid(cpu);
cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
+ cpu_clear(cpu, cpu_possible_map);
cpucount--;
} else {
per_cpu(x86_cpu_to_apicid, cpu) = apicid;
@@ -743,6 +744,7 @@ EXPORT_SYMBOL(xquad_portio);

static void __init disable_smp(void)
{
+ cpu_possible_map = cpumask_of_cpu(0);
smpboot_clear_io_apic_irqs();
phys_cpu_present_map = physid_mask_of_physid(0);
map_cpu_to_logical_apicid();
--
1.5.0.6

2008-03-19 20:32:18

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 58/79] [PATCH] include mach_apic.h in smpboot_64.c and smpboot.c

From: Glauber Costa <[email protected]>

After the inclusion, a lot of files needs fixing for conflicts,
some of them in the headers themselves, to accomodate for both
i386 and x86_64 versions.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/acpi/boot.c | 2 ++
arch/x86/kernel/mpparse_64.c | 2 ++
arch/x86/kernel/smpboot.c | 2 ++
arch/x86/kernel/smpboot_64.c | 1 +
arch/x86/vdso/Makefile | 2 +-
include/asm-x86/apic.h | 1 -
include/asm-x86/apicdef.h | 6 ------
include/asm-x86/mach-default/mach_apic.h | 11 +++++++++++
include/asm-x86/mach-default/mach_apicdef.h | 5 +++++
include/asm-x86/smp_64.h | 9 +--------
10 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e8c2c47..f1f7d18 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -40,6 +40,8 @@
#include <asm/io.h>
#include <asm/mpspec.h>

+#include <mach_apic.h>
+
static int __initdata acpi_force = 0;

#ifdef CONFIG_ACPI
diff --git a/arch/x86/kernel/mpparse_64.c b/arch/x86/kernel/mpparse_64.c
index 529b1c2..03ef1a8 100644
--- a/arch/x86/kernel/mpparse_64.c
+++ b/arch/x86/kernel/mpparse_64.c
@@ -30,6 +30,8 @@
#include <asm/proto.h>
#include <asm/acpi.h>

+#include <mach_apic.h>
+
/* Have we found an MP table */
int smp_found_config;
unsigned int __cpuinitdata maxcpus = NR_CPUS;
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6978f1b..253be86 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -11,6 +11,8 @@
#include <asm/cpu.h>
#include <asm/numa.h>

+#include <mach_apic.h>
+
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
EXPORT_SYMBOL(smp_num_siblings);
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 7d1b4cb..8a59fa8 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -61,6 +61,7 @@
#include <asm/numa.h>

#include <mach_wakecpu.h>
+#include <mach_apic.h>
#include <smpboot_hooks.h>

/* Set when the idlers are all forked */
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 0a8f474..17a6b05 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -39,7 +39,7 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE

CFL := $(PROFILING) -mcmodel=small -fPIC -g0 -O2 -fasynchronous-unwind-tables -m64

-$(vobjs): KBUILD_CFLAGS = $(CFL)
+$(vobjs): KBUILD_CFLAGS += $(CFL)

targets += vdso-syms.lds
obj-$(VDSO64-y) += vdso-syms.lds
diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h
index 0d6ea74..534af84 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -128,7 +128,6 @@ extern void enable_NMI_through_LVT0(void);
* On 32bit this is mach-xxx local
*/
#ifdef CONFIG_X86_64
-extern void setup_apic_routing(void);
extern void early_init_lapic_mapping(void);
#endif

diff --git a/include/asm-x86/apicdef.h b/include/asm-x86/apicdef.h
index b0c6b28..674a228 100644
--- a/include/asm-x86/apicdef.h
+++ b/include/asm-x86/apicdef.h
@@ -12,12 +12,6 @@

#define APIC_ID 0x20

-#ifdef CONFIG_X86_64
-# define APIC_ID_MASK (0xFFu<<24)
-# define GET_APIC_ID(x) (((x)>>24)&0xFFu)
-# define SET_APIC_ID(x) (((x)<<24))
-#endif
-
#define APIC_LVR 0x30
#define APIC_LVR_MASK 0xFF00FF
#define GET_APIC_VERSION(x) ((x)&0xFFu)
diff --git a/include/asm-x86/mach-default/mach_apic.h b/include/asm-x86/mach-default/mach_apic.h
index e3c2c10..e081bdc 100644
--- a/include/asm-x86/mach-default/mach_apic.h
+++ b/include/asm-x86/mach-default/mach_apic.h
@@ -54,21 +54,27 @@ static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
return phys_map;
}

+#ifdef CONFIG_X86_64
+extern void setup_apic_routing(void);
+#else
static inline void setup_apic_routing(void)
{
printk("Enabling APIC mode: %s. Using %d I/O APICs\n",
"Flat", nr_ioapics);
}
+#endif

static inline int multi_timer_check(int apic, int irq)
{
return 0;
}

+#ifdef CONFIG_X86_32
static inline int apicid_to_node(int logical_apicid)
{
return 0;
}
+#endif

/* Mapping from cpu number to logical apicid */
static inline int cpu_to_logical_apicid(int cpu)
@@ -78,8 +84,13 @@ static inline int cpu_to_logical_apicid(int cpu)

static inline int cpu_present_to_apicid(int mps_cpu)
{
+#ifdef CONFIG_X86_64
+ if (cpu_present(mps_cpu))
+ return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
+#else
if (mps_cpu < get_physical_broadcast())
return mps_cpu;
+#endif
else
return BAD_APICID;
}
diff --git a/include/asm-x86/mach-default/mach_apicdef.h b/include/asm-x86/mach-default/mach_apicdef.h
index ae98413..7b78275 100644
--- a/include/asm-x86/mach-default/mach_apicdef.h
+++ b/include/asm-x86/mach-default/mach_apicdef.h
@@ -3,7 +3,12 @@

#include <asm/apic.h>

+#ifdef CONFIG_X86_64
+#define APIC_ID_MASK (0xFFu<<24)
+#define SET_APIC_ID(x) (((x)<<24))
+#else
#define APIC_ID_MASK (0xF<<24)
+#endif

static inline unsigned get_apic_id(unsigned long x)
{
diff --git a/include/asm-x86/smp_64.h b/include/asm-x86/smp_64.h
index 1b3c0f1..be870a4 100644
--- a/include/asm-x86/smp_64.h
+++ b/include/asm-x86/smp_64.h
@@ -19,14 +19,6 @@ extern cpumask_t cpu_callin_map;
extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
void *info, int wait);

-static inline int cpu_present_to_apicid(int mps_cpu)
-{
- if (cpu_present(mps_cpu))
- return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
- else
- return BAD_APICID;
-}
-
#ifdef CONFIG_SMP

#define raw_smp_processor_id() read_pda(cpunumber)
@@ -64,6 +56,7 @@ static __inline int logical_smp_processor_id(void)
return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR));
}

+#include <mach_apicdef.h>
static inline int hard_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
--
1.5.0.6

2008-03-19 20:29:37

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 76/79] [PATCH] merge native_smp_prepare_cpus

From: Glauber Costa <[email protected]>

With the previous changes, code for native_smp_prepare_cpus()
in i386 and x86_64 now look very similar. merge them into
smpboot.c. Minor differences are inside ifdef

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 170 ++++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 137 ---------------------------------
arch/x86/kernel/smpboot_64.c | 141 ----------------------------------
3 files changed, 170 insertions(+), 278 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 26118b4..45119d3 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -7,6 +7,7 @@
#include <linux/err.h>
#include <linux/nmi.h>

+#include <asm/acpi.h>
#include <asm/desc.h>
#include <asm/nmi.h>
#include <asm/irq.h>
@@ -75,6 +76,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);

static atomic_t init_deasserted;

+static int boot_cpu_logical_apicid;
+
/* ready for x86_64, no harm for x86, since it will overwrite after alloc */
unsigned char *trampoline_base = __va(SMP_TRAMPOLINE_BASE);

@@ -1002,6 +1005,173 @@ int __cpuinit native_cpu_up(unsigned int cpu)
}

/*
+ * Fall back to non SMP mode after errors.
+ *
+ * RED-PEN audit/test this more. I bet there is more state messed up here.
+ */
+static __init void disable_smp(void)
+{
+ cpu_present_map = cpumask_of_cpu(0);
+ cpu_possible_map = cpumask_of_cpu(0);
+#ifdef CONFIG_X86_32
+ smpboot_clear_io_apic_irqs();
+#endif
+ if (smp_found_config)
+ phys_cpu_present_map =
+ physid_mask_of_physid(boot_cpu_physical_apicid);
+ else
+ phys_cpu_present_map = physid_mask_of_physid(0);
+ map_cpu_to_logical_apicid();
+ cpu_set(0, per_cpu(cpu_sibling_map, 0));
+ cpu_set(0, per_cpu(cpu_core_map, 0));
+}
+
+/*
+ * Various sanity checks.
+ */
+static int __init smp_sanity_check(unsigned max_cpus)
+{
+ if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
+ printk(KERN_WARNING "weird, boot CPU (#%d) not listed"
+ "by the BIOS.\n", hard_smp_processor_id());
+ physid_set(hard_smp_processor_id(), phys_cpu_present_map);
+ }
+
+ /*
+ * If we couldn't find an SMP configuration at boot time,
+ * get out of here now!
+ */
+ if (!smp_found_config && !acpi_lapic) {
+ printk(KERN_NOTICE "SMP motherboard not detected.\n");
+ disable_smp();
+ if (APIC_init_uniprocessor())
+ printk(KERN_NOTICE "Local APIC not detected."
+ " Using dummy APIC emulation.\n");
+ return -1;
+ }
+
+ /*
+ * Should not be necessary because the MP table should list the boot
+ * CPU too, but we do it for the sake of robustness anyway.
+ */
+ if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
+ printk(KERN_NOTICE
+ "weird, boot CPU (#%d) not listed by the BIOS.\n",
+ boot_cpu_physical_apicid);
+ physid_set(hard_smp_processor_id(), phys_cpu_present_map);
+ }
+
+ /*
+ * If we couldn't find a local APIC, then get out of here now!
+ */
+ if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) &&
+ !cpu_has_apic) {
+ printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
+ boot_cpu_physical_apicid);
+ printk(KERN_ERR "... forcing use of dummy APIC emulation."
+ "(tell your hw vendor)\n");
+ smpboot_clear_io_apic();
+ return -1;
+ }
+
+ verify_local_APIC();
+
+ /*
+ * If SMP should be disabled, then really disable it!
+ */
+ if (!max_cpus) {
+ printk(KERN_INFO "SMP mode deactivated,"
+ "forcing use of dummy APIC emulation.\n");
+ smpboot_clear_io_apic();
+#ifdef CONFIG_X86_32
+ if (nmi_watchdog == NMI_LOCAL_APIC) {
+ printk(KERN_INFO "activating minimal APIC for"
+ "NMI watchdog use.\n");
+ connect_bsp_APIC();
+ setup_local_APIC();
+ end_local_APIC_setup();
+ }
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __init smp_cpu_index_default(void)
+{
+ int i;
+ struct cpuinfo_x86 *c;
+
+ for_each_cpu_mask(i, cpu_possible_map) {
+ c = &cpu_data(i);
+ /* mark all to hotplug */
+ c->cpu_index = NR_CPUS;
+ }
+}
+
+/*
+ * Prepare for SMP bootup. The MP table or ACPI has been read
+ * earlier. Just do some sanity checking here and enable APIC mode.
+ */
+void __init native_smp_prepare_cpus(unsigned int max_cpus)
+{
+ nmi_watchdog_default();
+ smp_cpu_index_default();
+ current_cpu_data = boot_cpu_data;
+ cpu_callin_map = cpumask_of_cpu(0);
+ mb();
+ /*
+ * Setup boot CPU information
+ */
+ smp_store_cpu_info(0); /* Final full version of the data */
+ boot_cpu_logical_apicid = logical_smp_processor_id();
+ current_thread_info()->cpu = 0; /* needed? */
+ set_cpu_sibling_map(0);
+
+ if (smp_sanity_check(max_cpus) < 0) {
+ printk(KERN_INFO "SMP disabled\n");
+ disable_smp();
+ return;
+ }
+
+ if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
+ panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
+ GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
+ /* Or can we switch back to PIC here? */
+ }
+
+#ifdef CONFIG_X86_32
+ connect_bsp_APIC();
+#endif
+ /*
+ * Switch from PIC to APIC mode.
+ */
+ setup_local_APIC();
+
+#ifdef CONFIG_X86_64
+ /*
+ * Enable IO APIC before setting up error vector
+ */
+ if (!skip_ioapic_setup && nr_ioapics)
+ enable_IO_APIC();
+#endif
+ end_local_APIC_setup();
+
+ map_cpu_to_logical_apicid();
+
+ setup_portio_remap();
+
+ smpboot_setup_io_apic();
+ /*
+ * Set up local APIC timer on boot CPU.
+ */
+
+ printk(KERN_INFO "CPU%d: ", 0);
+ print_cpu_info(&cpu_data(0));
+ setup_boot_clock();
+}
+/*
* Early setup to make printk work.
*/
void __init native_smp_prepare_boot_cpu(void)
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5a0f57f..3a1b9e4 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -74,7 +74,6 @@ EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);

u8 apicid_2_node[MAX_APICID];

-extern void map_cpu_to_logical_apicid(void);
extern void unmap_cpu_to_logical_apicid(int cpu);

#ifdef CONFIG_HOTPLUG_CPU
@@ -94,144 +93,8 @@ void cpu_exit_clear(void)
}
#endif

-static int boot_cpu_logical_apicid;
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio;
#ifdef CONFIG_X86_NUMAQ
EXPORT_SYMBOL(xquad_portio);
#endif
-
-static void __init disable_smp(void)
-{
- cpu_possible_map = cpumask_of_cpu(0);
- cpu_present_map = cpumask_of_cpu(0);
- smpboot_clear_io_apic_irqs();
- if (smp_found_config)
- phys_cpu_present_map =
- physid_mask_of_physid(boot_cpu_physical_apicid);
- else
- phys_cpu_present_map = physid_mask_of_physid(0);
- map_cpu_to_logical_apicid();
- cpu_set(0, per_cpu(cpu_sibling_map, 0));
- cpu_set(0, per_cpu(cpu_core_map, 0));
-}
-
-static int __init smp_sanity_check(unsigned max_cpus)
-{
- if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
- printk(KERN_WARNING "weird, boot CPU (#%d) not listed"
- "by the BIOS.\n", hard_smp_processor_id());
- physid_set(hard_smp_processor_id(), phys_cpu_present_map);
- }
-
- /*
- * If we couldn't find an SMP configuration at boot time,
- * get out of here now!
- */
- if (!smp_found_config && !acpi_lapic) {
- printk(KERN_NOTICE "SMP motherboard not detected.\n");
- disable_smp();
- if (APIC_init_uniprocessor())
- printk(KERN_NOTICE "Local APIC not detected."
- " Using dummy APIC emulation.\n");
- return -1;
- }
-
- /*
- * Should not be necessary because the MP table should list the boot
- * CPU too, but we do it for the sake of robustness anyway.
- * Makes no sense to do this check in clustered apic mode, so skip it
- */
- if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
- printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
- boot_cpu_physical_apicid);
- physid_set(hard_smp_processor_id(), phys_cpu_present_map);
- }
-
- /*
- * If we couldn't find a local APIC, then get out of here now!
- */
- if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) {
- printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
- boot_cpu_physical_apicid);
- printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
- smpboot_clear_io_apic();
- return -1;
- }
-
- verify_local_APIC();
-
- /*
- * If SMP should be disabled, then really disable it!
- */
- if (!max_cpus) {
- smp_found_config = 0;
- printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
-
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- printk(KERN_INFO "activating minimal APIC for NMI watchdog use.\n");
- connect_bsp_APIC();
- setup_local_APIC();
- end_local_APIC_setup();
- }
- smpboot_clear_io_apic();
- return -1;
- }
- return 0;
-}
-
-static void __init smp_cpu_index_default(void)
-{
- int i;
- struct cpuinfo_x86 *c;
-
- for_each_cpu_mask(i, cpu_possible_map) {
- c = &cpu_data(i);
- /* mark all to hotplug */
- c->cpu_index = NR_CPUS;
- }
-}
-
-void __init native_smp_prepare_cpus(unsigned int max_cpus)
-{
- nmi_watchdog_default();
- smp_cpu_index_default();
- current_cpu_data = boot_cpu_data;
- cpu_callin_map = cpumask_of_cpu(0);
- mb();
-
- /*
- * Setup boot CPU information
- */
- smp_store_cpu_info(0); /* Final full version of the data */
- boot_cpu_logical_apicid = logical_smp_processor_id();
- current_thread_info()->cpu = 0;
-
- set_cpu_sibling_map(0);
-
- if (smp_sanity_check(max_cpus) < 0) {
- printk(KERN_INFO "SMP disabled\n");
- disable_smp();
- return;
- }
-
- if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
- panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
- GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
- /* Or can we switch back to PIC here? */
- }
-
- connect_bsp_APIC();
- setup_local_APIC();
- end_local_APIC_setup();
- map_cpu_to_logical_apicid();
-
- setup_portio_remap();
-
- smpboot_setup_io_apic();
-
- printk(KERN_INFO "CPU%d: ", 0);
- print_cpu_info(&cpu_data(0));
- setup_boot_clock();
-}
-
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 7752445..66b5562 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -71,144 +71,3 @@ int smp_threads_ready;

cycles_t cacheflush_time;
unsigned long cache_decay_ticks;
-
-static int boot_cpu_logical_apicid;
-/*
- * Fall back to non SMP mode after errors.
- *
- * RED-PEN audit/test this more. I bet there is more state messed up here.
- */
-static __init void disable_smp(void)
-{
- cpu_present_map = cpumask_of_cpu(0);
- cpu_possible_map = cpumask_of_cpu(0);
- if (smp_found_config)
- phys_cpu_present_map =
- physid_mask_of_physid(boot_cpu_physical_apicid);
- else
- phys_cpu_present_map = physid_mask_of_physid(0);
- cpu_set(0, per_cpu(cpu_sibling_map, 0));
- cpu_set(0, per_cpu(cpu_core_map, 0));
-}
-
-/*
- * Various sanity checks.
- */
-static int __init smp_sanity_check(unsigned max_cpus)
-{
- if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
- printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
- hard_smp_processor_id());
- physid_set(hard_smp_processor_id(), phys_cpu_present_map);
- }
-
- /*
- * If we couldn't find an SMP configuration at boot time,
- * get out of here now!
- */
- if (!smp_found_config && !acpi_lapic) {
- printk(KERN_NOTICE "SMP motherboard not detected.\n");
- disable_smp();
- if (APIC_init_uniprocessor())
- printk(KERN_NOTICE "Local APIC not detected."
- " Using dummy APIC emulation.\n");
- return -1;
- }
-
- /*
- * Should not be necessary because the MP table should list the boot
- * CPU too, but we do it for the sake of robustness anyway.
- */
- if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
- printk(KERN_NOTICE
- "weird, boot CPU (#%d) not listed by the BIOS.\n",
- boot_cpu_physical_apicid);
- physid_set(hard_smp_processor_id(), phys_cpu_present_map);
- }
-
- /*
- * If we couldn't find a local APIC, then get out of here now!
- */
- if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) &&
- !cpu_has_apic) {
- printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
- boot_cpu_physical_apicid);
- printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
- smpboot_clear_io_apic();
- return -1;
- }
-
- verify_local_APIC();
-
- /*
- * If SMP should be disabled, then really disable it!
- */
- if (!max_cpus) {
- printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
- smpboot_clear_io_apic();
- return -1;
- }
-
- return 0;
-}
-
-static void __init smp_cpu_index_default(void)
-{
- int i;
- struct cpuinfo_x86 *c;
-
- for_each_cpu_mask(i, cpu_possible_map) {
- c = &cpu_data(i);
- /* mark all to hotplug */
- c->cpu_index = NR_CPUS;
- }
-}
-
-/*
- * Prepare for SMP bootup. The MP table or ACPI has been read
- * earlier. Just do some sanity checking here and enable APIC mode.
- */
-void __init native_smp_prepare_cpus(unsigned int max_cpus)
-{
- nmi_watchdog_default();
- smp_cpu_index_default();
- cpu_callin_map = cpumask_of_cpu(0);
- mb();
-
- current_cpu_data = boot_cpu_data;
- boot_cpu_logical_apicid = logical_smp_processor_id();
- current_thread_info()->cpu = 0; /* needed? */
- set_cpu_sibling_map(0);
-
- if (smp_sanity_check(max_cpus) < 0) {
- printk(KERN_INFO "SMP disabled\n");
- disable_smp();
- return;
- }
-
- if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
- panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
- GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
- /* Or can we switch back to PIC here? */
- }
-
- /*
- * Switch from PIC to APIC mode.
- */
- setup_local_APIC();
-
- /*
- * Enable IO APIC before setting up error vector
- */
- if (!skip_ioapic_setup && nr_ioapics)
- enable_IO_APIC();
- end_local_APIC_setup();
-
- /*
- * Set up local APIC timer on boot CPU.
- */
-
- setup_boot_clock();
- printk(KERN_INFO "CPU%d: ", 0);
- print_cpu_info(&cpu_data(0));
-}
--
1.5.0.6

2008-03-19 20:29:04

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 63/79] [PATCH] change boot_cpu_id to boot_cpu_physical_apicid

From: Glauber Costa <[email protected]>

This is to match i386. The former name was cuter,
but the current is more meaningful and more general,
since cpu_id can be a logical id.

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/apic_64.c | 13 +++++++------
arch/x86/kernel/mpparse_64.c | 12 ++++++------
arch/x86/kernel/smpboot_64.c | 18 ++++++++++--------
arch/x86/mm/k8topology_64.c | 7 ++++---
include/asm-x86/apic.h | 1 -
include/asm-x86/smp.h | 3 +++
include/asm-x86/smp_32.h | 5 -----
include/asm-x86/smp_64.h | 4 ----
8 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 8a47579..868ec1d 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -431,7 +431,8 @@ void __cpuinit check_boot_apic_timer_broadcast(void)
lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;

local_irq_enable();
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
+ &boot_cpu_physical_apicid);
local_irq_disable();
}

@@ -857,7 +858,7 @@ static int __init detect_init_APIC(void)
}

mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
- boot_cpu_id = 0;
+ boot_cpu_physical_apicid = 0;
return 0;
}

@@ -882,7 +883,7 @@ void __init early_init_lapic_mapping(void)
* Fetch the APIC ID of the BSP in case we have a
* default configuration (or the MP table is broken).
*/
- boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
}

/**
@@ -909,7 +910,7 @@ void __init init_apic_mappings(void)
* Fetch the APIC ID of the BSP in case we have a
* default configuration (or the MP table is broken).
*/
- boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
}

/*
@@ -930,8 +931,8 @@ int __init APIC_init_uniprocessor(void)

verify_local_APIC();

- phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
- apic_write(APIC_ID, SET_APIC_ID(boot_cpu_id));
+ phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
+ apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid));

setup_local_APIC();

diff --git a/arch/x86/kernel/mpparse_64.c b/arch/x86/kernel/mpparse_64.c
index 03ef1a8..20a345d 100644
--- a/arch/x86/kernel/mpparse_64.c
+++ b/arch/x86/kernel/mpparse_64.c
@@ -59,8 +59,8 @@ unsigned long mp_lapic_addr = 0;


/* Processor that is doing the boot up */
-unsigned int boot_cpu_id = -1U;
-EXPORT_SYMBOL(boot_cpu_id);
+unsigned int boot_cpu_physical_apicid = -1U;
+EXPORT_SYMBOL(boot_cpu_physical_apicid);

/* Internal processor count */
unsigned int num_processors;
@@ -107,7 +107,7 @@ static void __cpuinit MP_processor_info(struct mpc_config_processor *m)
}
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
bootup_cpu = " (Bootup-CPU)";
- boot_cpu_id = m->mpc_apicid;
+ boot_cpu_physical_apicid = m->mpc_apicid;
}

printk(KERN_INFO "Processor #%d%s\n", m->mpc_apicid, bootup_cpu);
@@ -665,8 +665,8 @@ void __init mp_register_lapic_address(u64 address)
{
mp_lapic_addr = (unsigned long) address;
set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
- if (boot_cpu_id == -1U)
- boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+ if (boot_cpu_physical_apicid == -1U)
+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
}

void __cpuinit mp_register_lapic (u8 id, u8 enabled)
@@ -674,7 +674,7 @@ void __cpuinit mp_register_lapic (u8 id, u8 enabled)
struct mpc_config_processor processor;
int boot_cpu = 0;

- if (id == boot_cpu_id)
+ if (id == boot_cpu_physical_apicid)
boot_cpu = 1;

processor.mpc_type = MP_PROCESSOR;
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 7ec9621..420ae4a 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -602,7 +602,8 @@ static __init void disable_smp(void)
cpu_present_map = cpumask_of_cpu(0);
cpu_possible_map = cpumask_of_cpu(0);
if (smp_found_config)
- phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
+ phys_cpu_present_map =
+ physid_mask_of_physid(boot_cpu_physical_apicid);
else
phys_cpu_present_map = physid_mask_of_physid(0);
cpu_set(0, per_cpu(cpu_sibling_map, 0));
@@ -637,9 +638,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
* Should not be necessary because the MP table should list the boot
* CPU too, but we do it for the sake of robustness anyway.
*/
- if (!physid_isset(boot_cpu_id, phys_cpu_present_map)) {
- printk(KERN_NOTICE "weird, boot CPU (#%d) not listed by the BIOS.\n",
- boot_cpu_id);
+ if (!physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map)) {
+ printk(KERN_NOTICE
+ "weird, boot CPU (#%d) not listed by the BIOS.\n",
+ boot_cpu_physical_apicid);
physid_set(hard_smp_processor_id(), phys_cpu_present_map);
}

@@ -648,7 +650,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
*/
if (!cpu_has_apic) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
- boot_cpu_id);
+ boot_cpu_physical_apicid);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
nr_ioapics = 0;
return -1;
@@ -709,9 +711,9 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
enable_IO_APIC();
end_local_APIC_setup();

- if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id) {
+ if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) {
panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
- GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_id);
+ GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_physical_apicid);
/* Or can we switch back to PIC here? */
}

@@ -756,7 +758,7 @@ int __cpuinit native_cpu_up(unsigned int cpu)

Dprintk("++++++++++++++++++++=_---CPU UP %u\n", cpu);

- if (apicid == BAD_APICID || apicid == boot_cpu_id ||
+ if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
!physid_isset(apicid, phys_cpu_present_map)) {
printk("__cpu_up: bad cpu %d\n", cpu);
return -EINVAL;
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c
index be72dd2..1f249f1 100644
--- a/arch/x86/mm/k8topology_64.c
+++ b/arch/x86/mm/k8topology_64.c
@@ -205,9 +205,10 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
apicid_base = 0;
/* need to get boot_cpu_id early for system with apicid lifting */
early_get_boot_cpu_id();
- if (boot_cpu_id > 0) {
- printk(KERN_INFO "BSP APIC ID: %02x\n", boot_cpu_id);
- apicid_base = boot_cpu_id;
+ if (boot_cpu_physical_apicid > 0) {
+ printk(KERN_INFO "BSP APIC ID: %02x\n",
+ boot_cpu_physical_apicid);
+ apicid_base = boot_cpu_physical_apicid;
}

for (i = 0; i < 8; i++) {
diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h
index 534af84..95676b6 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -44,7 +44,6 @@ extern int apic_runs_main_timer;
extern int ioapic_force;
extern int disable_apic;
extern int disable_apic_timer;
-extern unsigned boot_cpu_id;

/*
* Basic functions accessing APICs.
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 78ef16d..2ad2f4f 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -109,6 +109,9 @@ extern void prefill_possible_map(void);
extern unsigned long setup_trampoline(void);

void smp_store_cpu_info(int id);
+#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)
+#else
+#define cpu_physical_id(cpu) boot_cpu_physical_apicid
#endif

#ifdef CONFIG_X86_32
diff --git a/include/asm-x86/smp_32.h b/include/asm-x86/smp_32.h
index 478f556..f861d04 100644
--- a/include/asm-x86/smp_32.h
+++ b/include/asm-x86/smp_32.h
@@ -30,8 +30,6 @@ extern void zap_low_mappings (void);
DECLARE_PER_CPU(int, cpu_number);
#define raw_smp_processor_id() (x86_read_percpu(cpu_number))

-#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)
-
extern int safe_smp_processor_id(void);

/* We don't mark CPUs online until __cpu_up(), so we need another measure */
@@ -41,10 +39,7 @@ static inline int num_booting_cpus(void)
}

#else /* CONFIG_SMP */
-
#define safe_smp_processor_id() 0
-#define cpu_physical_id(cpu) boot_cpu_physical_apicid
-
#endif /* !CONFIG_SMP */

#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-x86/smp_64.h b/include/asm-x86/smp_64.h
index be870a4..fd709cb 100644
--- a/include/asm-x86/smp_64.h
+++ b/include/asm-x86/smp_64.h
@@ -22,7 +22,6 @@ extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
#ifdef CONFIG_SMP

#define raw_smp_processor_id() read_pda(cpunumber)
-#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)

#define stack_smp_processor_id() \
({ \
@@ -41,9 +40,6 @@ static inline int num_booting_cpus(void)
}

#else /* CONFIG_SMP */
-
-extern unsigned int boot_cpu_id;
-#define cpu_physical_id(cpu) boot_cpu_id
#define stack_smp_processor_id() 0

#endif /* !CONFIG_SMP */
--
1.5.0.6

2008-03-19 20:33:09

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 64/79] [PATCH] integrate do_boot_cpu

From: Glauber Costa <[email protected]>

This is a very large patch, because it depends on a lot
of auxiliary static functions. But they all have been modified
to the point that they're sufficiently close now. So they're just
merged in smpboot.c

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 588 ++++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 532 +-------------------------------------
arch/x86/kernel/smpboot_64.c | 515 +------------------------------------
include/asm-x86/smp.h | 3 +
4 files changed, 594 insertions(+), 1044 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 5bff87e..69c1796 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -4,14 +4,42 @@
#include <linux/sched.h>
#include <linux/percpu.h>
#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <linux/nmi.h>

+#include <asm/desc.h>
#include <asm/nmi.h>
#include <asm/irq.h>
#include <asm/smp.h>
#include <asm/cpu.h>
#include <asm/numa.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/mtrr.h>
+#include <asm/nmi.h>
+#include <linux/mc146818rtc.h>

#include <mach_apic.h>
+#include <mach_wakecpu.h>
+#include <smpboot_hooks.h>
+
+/* Store all idle threads, this can be reused instead of creating
+* a new thread. Also avoids complicated thread destroy functionality
+* for idle threads.
+*/
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Needed only for CONFIG_HOTPLUG_CPU because __cpuinitdata is
+ * removed after init for !CONFIG_HOTPLUG_CPU.
+ */
+static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
+#define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x))
+#define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p))
+#else
+struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
+#define get_idle_for_cpu(x) (idle_thread_array[(x)])
+#define set_idle_for_cpu(x, p) (idle_thread_array[(x)] = (p))
+#endif

/* Number of siblings per CPU package */
int smp_num_siblings = 1;
@@ -41,6 +69,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_core_map);
DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
EXPORT_PER_CPU_SYMBOL(cpu_info);

+static atomic_t init_deasserted;
+
/* ready for x86_64, no harm for x86, since it will overwrite after alloc */
unsigned char *trampoline_base = __va(SMP_TRAMPOLINE_BASE);

@@ -110,6 +140,96 @@ void unmap_cpu_to_logical_apicid(int cpu)
#define map_cpu_to_logical_apicid() do {} while (0)
#endif

+/*
+ * Report back to the Boot Processor.
+ * Running on AP.
+ */
+void __cpuinit smp_callin(void)
+{
+ int cpuid, phys_id;
+ unsigned long timeout;
+
+ /*
+ * If waken up by an INIT in an 82489DX configuration
+ * we may get here before an INIT-deassert IPI reaches
+ * our local APIC. We have to wait for the IPI or we'll
+ * lock up on an APIC access.
+ */
+ wait_for_init_deassert(&init_deasserted);
+
+ /*
+ * (This works even if the APIC is not enabled.)
+ */
+ phys_id = GET_APIC_ID(apic_read(APIC_ID));
+ cpuid = smp_processor_id();
+ if (cpu_isset(cpuid, cpu_callin_map)) {
+ panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
+ phys_id, cpuid);
+ }
+ Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
+
+ /*
+ * STARTUP IPIs are fragile beasts as they might sometimes
+ * trigger some glue motherboard logic. Complete APIC bus
+ * silence for 1 second, this overestimates the time the
+ * boot CPU is spending to send the up to 2 STARTUP IPIs
+ * by a factor of two. This should be enough.
+ */
+
+ /*
+ * Waiting 2s total for startup (udelay is not yet working)
+ */
+ timeout = jiffies + 2*HZ;
+ while (time_before(jiffies, timeout)) {
+ /*
+ * Has the boot CPU finished it's STARTUP sequence?
+ */
+ if (cpu_isset(cpuid, cpu_callout_map))
+ break;
+ cpu_relax();
+ }
+
+ if (!time_before(jiffies, timeout)) {
+ panic("%s: CPU%d started up but did not get a callout!\n",
+ __func__, cpuid);
+ }
+
+ /*
+ * the boot CPU has finished the init stage and is spinning
+ * on callin_map until we finish. We are free to set up this
+ * CPU, first the APIC. (this is probably redundant on most
+ * boards)
+ */
+
+ Dprintk("CALLIN, before setup_local_APIC().\n");
+ smp_callin_clear_local_apic();
+ setup_local_APIC();
+ end_local_APIC_setup();
+ map_cpu_to_logical_apicid();
+
+ /*
+ * Get our bogomips.
+ *
+ * Need to enable IRQs because it can take longer and then
+ * the NMI watchdog might kill us.
+ */
+ local_irq_enable();
+ calibrate_delay();
+ local_irq_disable();
+ Dprintk("Stack at about %p\n", &cpuid);
+
+ /*
+ * Save our processor parameters
+ */
+ smp_store_cpu_info(cpuid);
+
+ /*
+ * Allow the master to continue.
+ */
+ cpu_set(cpuid, cpu_callin_map);
+}
+
+
static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_X86_32
@@ -327,6 +447,474 @@ void impress_friends(void)
Dprintk("Before bogocount - setting activated=1.\n");
}

+static inline void __inquire_remote_apic(int apicid)
+{
+ unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
+ char *names[] = { "ID", "VERSION", "SPIV" };
+ int timeout;
+ u32 status;
+
+ printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ printk(KERN_INFO "... APIC #%d %s: ", apicid, names[i]);
+
+ /*
+ * Wait for idle.
+ */
+ status = safe_apic_wait_icr_idle();
+ if (status)
+ printk(KERN_CONT
+ "a previous APIC delivery may have failed\n");
+
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+ apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
+
+ timeout = 0;
+ do {
+ udelay(100);
+ status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+ } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+ switch (status) {
+ case APIC_ICR_RR_VALID:
+ status = apic_read(APIC_RRR);
+ printk(KERN_CONT "%08x\n", status);
+ break;
+ default:
+ printk(KERN_CONT "failed\n");
+ }
+ }
+}
+
+#ifdef WAKE_SECONDARY_VIA_NMI
+/*
+ * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
+ * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
+ * won't ... remember to clear down the APIC, etc later.
+ */
+static int __devinit
+wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
+{
+ unsigned long send_status, accept_status = 0;
+ int maxlvt;
+
+ /* Target chip */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
+
+ /* Boot on the stack */
+ /* Kick the second */
+ apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
+
+ Dprintk("Waiting for send to finish...\n");
+ send_status = safe_apic_wait_icr_idle();
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(200);
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ maxlvt = lapic_get_maxlvt();
+ if (maxlvt > 3) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ }
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ Dprintk("NMI sent.\n");
+
+ if (send_status)
+ printk(KERN_ERR "APIC never delivered???\n");
+ if (accept_status)
+ printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
+
+ return (send_status | accept_status);
+}
+#endif /* WAKE_SECONDARY_VIA_NMI */
+
+extern void start_secondary(void *unused);
+#ifdef WAKE_SECONDARY_VIA_INIT
+static int __devinit
+wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
+{
+ unsigned long send_status, accept_status = 0;
+ int maxlvt, num_starts, j;
+
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+ if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ }
+
+ Dprintk("Asserting INIT.\n");
+
+ /*
+ * Turn INIT on target chip
+ */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+
+ /*
+ * Send IPI
+ */
+ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+ | APIC_DM_INIT);
+
+ Dprintk("Waiting for send to finish...\n");
+ send_status = safe_apic_wait_icr_idle();
+
+ mdelay(10);
+
+ Dprintk("Deasserting INIT.\n");
+
+ /* Target chip */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+
+ /* Send IPI */
+ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+
+ Dprintk("Waiting for send to finish...\n");
+ send_status = safe_apic_wait_icr_idle();
+
+ mb();
+ atomic_set(&init_deasserted, 1);
+
+ /*
+ * Should we send STARTUP IPIs ?
+ *
+ * Determine this based on the APIC version.
+ * If we don't have an integrated APIC, don't send the STARTUP IPIs.
+ */
+ if (APIC_INTEGRATED(apic_version[phys_apicid]))
+ num_starts = 2;
+ else
+ num_starts = 0;
+
+ /*
+ * Paravirt / VMI wants a startup IPI hook here to set up the
+ * target processor state.
+ */
+ startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
+#ifdef CONFIG_X86_64
+ (unsigned long)init_rsp);
+#else
+ (unsigned long)stack_start.sp);
+#endif
+
+ /*
+ * Run STARTUP IPI loop.
+ */
+ Dprintk("#startup loops: %d.\n", num_starts);
+
+ maxlvt = lapic_get_maxlvt();
+
+ for (j = 1; j <= num_starts; j++) {
+ Dprintk("Sending STARTUP #%d.\n", j);
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ Dprintk("After apic_write.\n");
+
+ /*
+ * STARTUP IPI
+ */
+
+ /* Target chip */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+
+ /* Boot on the stack */
+ /* Kick the second */
+ apic_write_around(APIC_ICR, APIC_DM_STARTUP
+ | (start_eip >> 12));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(300);
+
+ Dprintk("Startup point 1.\n");
+
+ Dprintk("Waiting for send to finish...\n");
+ send_status = safe_apic_wait_icr_idle();
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(200);
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ if (maxlvt > 3) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ }
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ if (send_status || accept_status)
+ break;
+ }
+ Dprintk("After Startup.\n");
+
+ if (send_status)
+ printk(KERN_ERR "APIC never delivered???\n");
+ if (accept_status)
+ printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
+
+ return (send_status | accept_status);
+}
+#endif /* WAKE_SECONDARY_VIA_INIT */
+
+struct create_idle {
+ struct work_struct work;
+ struct task_struct *idle;
+ struct completion done;
+ int cpu;
+};
+
+static void __cpuinit do_fork_idle(struct work_struct *work)
+{
+ struct create_idle *c_idle =
+ container_of(work, struct create_idle, work);
+
+ c_idle->idle = fork_idle(c_idle->cpu);
+ complete(&c_idle->done);
+}
+
+static int __cpuinit do_boot_cpu(int apicid, int cpu)
+/*
+ * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
+ * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
+ * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu.
+ */
+{
+ unsigned long boot_error = 0;
+ int timeout;
+ unsigned long start_ip;
+ unsigned short nmi_high = 0, nmi_low = 0;
+ struct create_idle c_idle = {
+ .cpu = cpu,
+ .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
+ };
+ INIT_WORK(&c_idle.work, do_fork_idle);
+#ifdef CONFIG_X86_64
+ /* allocate memory for gdts of secondary cpus. Hotplug is considered */
+ if (!cpu_gdt_descr[cpu].address &&
+ !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) {
+ printk(KERN_ERR "Failed to allocate GDT for CPU %d\n", cpu);
+ return -1;
+ }
+
+ /* Allocate node local memory for AP pdas */
+ if (cpu_pda(cpu) == &boot_cpu_pda[cpu]) {
+ struct x8664_pda *newpda, *pda;
+ int node = cpu_to_node(cpu);
+ pda = cpu_pda(cpu);
+ newpda = kmalloc_node(sizeof(struct x8664_pda), GFP_ATOMIC,
+ node);
+ if (newpda) {
+ memcpy(newpda, pda, sizeof(struct x8664_pda));
+ cpu_pda(cpu) = newpda;
+ } else
+ printk(KERN_ERR
+ "Could not allocate node local PDA for CPU %d on node %d\n",
+ cpu, node);
+ }
+#endif
+
+ alternatives_smp_switch(1);
+
+ c_idle.idle = get_idle_for_cpu(cpu);
+
+ /*
+ * We can't use kernel_thread since we must avoid to
+ * reschedule the child.
+ */
+ if (c_idle.idle) {
+ c_idle.idle->thread.sp = (unsigned long) (((struct pt_regs *)
+ (THREAD_SIZE + task_stack_page(c_idle.idle))) - 1);
+ init_idle(c_idle.idle, cpu);
+ goto do_rest;
+ }
+
+ if (!keventd_up() || current_is_keventd())
+ c_idle.work.func(&c_idle.work);
+ else {
+ schedule_work(&c_idle.work);
+ wait_for_completion(&c_idle.done);
+ }
+
+ if (IS_ERR(c_idle.idle)) {
+ printk("failed fork for CPU %d\n", cpu);
+ return PTR_ERR(c_idle.idle);
+ }
+
+ set_idle_for_cpu(cpu, c_idle.idle);
+do_rest:
+#ifdef CONFIG_X86_32
+ per_cpu(current_task, cpu) = c_idle.idle;
+ init_gdt(cpu);
+ early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
+ c_idle.idle->thread.ip = (unsigned long) start_secondary;
+ /* Stack for startup_32 can be just as for start_secondary onwards */
+ stack_start.sp = (void *) c_idle.idle->thread.sp;
+ irq_ctx_init(cpu);
+#else
+ cpu_pda(cpu)->pcurrent = c_idle.idle;
+ init_rsp = c_idle.idle->thread.sp;
+ load_sp0(&per_cpu(init_tss, cpu), &c_idle.idle->thread);
+ initial_code = (unsigned long)start_secondary;
+ clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
+#endif
+
+ /* start_ip had better be page-aligned! */
+ start_ip = setup_trampoline();
+
+ /* So we see what's up */
+ printk(KERN_INFO "Booting processor %d/%d ip %lx\n",
+ cpu, apicid, start_ip);
+
+ /*
+ * This grunge runs the startup process for
+ * the targeted processor.
+ */
+
+ atomic_set(&init_deasserted, 0);
+
+ Dprintk("Setting warm reset code and vector.\n");
+
+ store_NMI_vector(&nmi_high, &nmi_low);
+
+ smpboot_setup_warm_reset_vector(start_ip);
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+
+
+ /*
+ * Starting actual IPI sequence...
+ */
+ boot_error = wakeup_secondary_cpu(apicid, start_ip);
+
+ if (!boot_error) {
+ /*
+ * allow APs to start initializing.
+ */
+ Dprintk("Before Callout %d.\n", cpu);
+ cpu_set(cpu, cpu_callout_map);
+ Dprintk("After Callout %d.\n", cpu);
+
+ /*
+ * Wait 5s total for a response
+ */
+ for (timeout = 0; timeout < 50000; timeout++) {
+ if (cpu_isset(cpu, cpu_callin_map))
+ break; /* It has booted */
+ udelay(100);
+ }
+
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ /* number CPUs logically, starting from 1 (BSP is 0) */
+ Dprintk("OK.\n");
+ printk(KERN_INFO "CPU%d: ", cpu);
+ print_cpu_info(&cpu_data(cpu));
+ Dprintk("CPU has booted.\n");
+ } else {
+ boot_error = 1;
+ if (*((volatile unsigned char *)trampoline_base)
+ == 0xA5)
+ /* trampoline started but...? */
+ printk(KERN_ERR "Stuck ??\n");
+ else
+ /* trampoline code not run */
+ printk(KERN_ERR "Not responding.\n");
+ inquire_remote_apic(apicid);
+ }
+ }
+
+ if (boot_error) {
+ /* Try to put things back the way they were before ... */
+ unmap_cpu_to_logical_apicid(cpu);
+#ifdef CONFIG_X86_64
+ clear_node_cpumask(cpu); /* was set by numa_add_cpu */
+#endif
+ cpu_clear(cpu, cpu_callout_map); /* was set by do_boot_cpu() */
+ cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
+ cpu_clear(cpu, cpu_possible_map);
+ cpu_clear(cpu, cpu_present_map);
+ per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
+ }
+
+ /* mark "stuck" area as not stuck */
+ *((volatile unsigned long *)trampoline_base) = 0;
+
+ return boot_error;
+}
+
+int __cpuinit native_cpu_up(unsigned int cpu)
+{
+ int apicid = cpu_present_to_apicid(cpu);
+ unsigned long flags;
+ int err;
+
+ WARN_ON(irqs_disabled());
+
+ Dprintk("++++++++++++++++++++=_---CPU UP %u\n", cpu);
+
+ if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
+ !physid_isset(apicid, phys_cpu_present_map)) {
+ printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu);
+ return -EINVAL;
+ }
+
+ /*
+ * Already booted CPU?
+ */
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ Dprintk("do_boot_cpu %d Already started\n", cpu);
+ return -ENOSYS;
+ }
+
+ /*
+ * Save current MTRR state in case it was changed since early boot
+ * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
+ */
+ mtrr_save_state();
+
+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+
+#ifdef CONFIG_X86_32
+ /* init low mem mapping */
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+ flush_tlb_all();
+#endif
+
+ err = do_boot_cpu(apicid, cpu);
+ if (err < 0) {
+ Dprintk("do_boot_cpu failed %d\n", err);
+ return err;
+ }
+
+ /*
+ * Check TSC synchronization with the AP (keep irqs disabled
+ * while doing so):
+ */
+ local_irq_save(flags);
+ check_tsc_sync_source(cpu);
+ local_irq_restore(flags);
+
+ while (!cpu_isset(cpu, cpu_online_map)) {
+ cpu_relax();
+ touch_nmi_watchdog();
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
void remove_siblinginfo(int cpu)
{
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index ae25927..e82eeb2 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -80,114 +80,12 @@ extern void unmap_cpu_to_logical_apicid(int cpu);
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

-/* Store all idle threads, this can be reused instead of creating
-* a new thread. Also avoids complicated thread destroy functionality
-* for idle threads.
-*/
-#ifdef CONFIG_HOTPLUG_CPU
-/*
- * Needed only for CONFIG_HOTPLUG_CPU because __cpuinitdata is
- * removed after init for !CONFIG_HOTPLUG_CPU.
- */
-static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
-#define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x))
-#define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p))
-#else
-struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
-#define get_idle_for_cpu(x) (idle_thread_array[(x)])
-#define set_idle_for_cpu(x, p) (idle_thread_array[(x)] = (p))
-#endif
-
-static atomic_t init_deasserted;
-
-static void __cpuinit smp_callin(void)
-{
- int cpuid, phys_id;
- unsigned long timeout;
-
- /*
- * If waken up by an INIT in an 82489DX configuration
- * we may get here before an INIT-deassert IPI reaches
- * our local APIC. We have to wait for the IPI or we'll
- * lock up on an APIC access.
- */
- wait_for_init_deassert(&init_deasserted);
-
- /*
- * (This works even if the APIC is not enabled.)
- */
- phys_id = GET_APIC_ID(apic_read(APIC_ID));
- cpuid = smp_processor_id();
- if (cpu_isset(cpuid, cpu_callin_map)) {
- printk("huh, phys CPU#%d, CPU#%d already present??\n",
- phys_id, cpuid);
- BUG();
- }
- Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
-
- /*
- * STARTUP IPIs are fragile beasts as they might sometimes
- * trigger some glue motherboard logic. Complete APIC bus
- * silence for 1 second, this overestimates the time the
- * boot CPU is spending to send the up to 2 STARTUP IPIs
- * by a factor of two. This should be enough.
- */
-
- /*
- * Waiting 2s total for startup (udelay is not yet working)
- */
- timeout = jiffies + 2*HZ;
- while (time_before(jiffies, timeout)) {
- /*
- * Has the boot CPU finished it's STARTUP sequence?
- */
- if (cpu_isset(cpuid, cpu_callout_map))
- break;
- cpu_relax();
- }
-
- if (!time_before(jiffies, timeout)) {
- printk("BUG: CPU%d started up but did not get a callout!\n",
- cpuid);
- BUG();
- }
-
- /*
- * the boot CPU has finished the init stage and is spinning
- * on callin_map until we finish. We are free to set up this
- * CPU, first the APIC. (this is probably redundant on most
- * boards)
- */
-
- Dprintk("CALLIN, before setup_local_APIC().\n");
- smp_callin_clear_local_apic();
- setup_local_APIC();
- end_local_APIC_setup();
- map_cpu_to_logical_apicid();
-
- /*
- * Get our bogomips.
- */
- local_irq_enable();
- calibrate_delay();
- local_irq_disable();
- Dprintk("Stack at about %p\n",&cpuid);
-
- /*
- * Save our processor parameters
- */
- smp_store_cpu_info(cpuid);
-
- /*
- * Allow the master to continue.
- */
- cpu_set(cpuid, cpu_callin_map);
-}
+extern void smp_callin(void);

/*
* Activate a secondary processor.
*/
-static void __cpuinit start_secondary(void *unused)
+void __cpuinit start_secondary(void *unused)
{
/*
* Don't put *anything* before cpu_init(), SMP booting is too
@@ -257,373 +155,6 @@ void __devinit initialize_secondary(void)
:"m" (current->thread.sp),"m" (current->thread.ip));
}

-static inline void __inquire_remote_apic(int apicid)
-{
- unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
- char *names[] = { "ID", "VERSION", "SPIV" };
- int timeout;
- u32 status;
-
- printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);
-
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- printk(KERN_INFO "... APIC #%d %s: ", apicid, names[i]);
-
- /*
- * Wait for idle.
- */
- status = safe_apic_wait_icr_idle();
- if (status)
- printk(KERN_CONT
- "a previous APIC delivery may have failed\n");
-
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
-
- timeout = 0;
- do {
- udelay(100);
- status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
- } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
-
- switch (status) {
- case APIC_ICR_RR_VALID:
- status = apic_read(APIC_RRR);
- printk(KERN_CONT "%08x\n", status);
- break;
- default:
- printk(KERN_CONT "failed\n");
- }
- }
-}
-
-#ifdef WAKE_SECONDARY_VIA_NMI
-/*
- * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
- * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
- * won't ... remember to clear down the APIC, etc later.
- */
-static int __devinit
-wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
-{
- unsigned long send_status, accept_status = 0;
- int maxlvt;
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
-
- /* Boot on the stack */
- /* Kick the second */
- apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(200);
- /*
- * Due to the Pentium erratum 3AP.
- */
- maxlvt = lapic_get_maxlvt();
- if (maxlvt > 3) {
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- }
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- Dprintk("NMI sent.\n");
-
- if (send_status)
- printk("APIC never delivered???\n");
- if (accept_status)
- printk("APIC delivery error (%lx).\n", accept_status);
-
- return (send_status | accept_status);
-}
-#endif /* WAKE_SECONDARY_VIA_NMI */
-
-#ifdef WAKE_SECONDARY_VIA_INIT
-static int __devinit
-wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
-{
- unsigned long send_status, accept_status = 0;
- int maxlvt, num_starts, j;
-
- /*
- * Be paranoid about clearing APIC errors.
- */
- if (APIC_INTEGRATED(apic_version[phys_apicid])) {
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
- }
-
- Dprintk("Asserting INIT.\n");
-
- /*
- * Turn INIT on target chip
- */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
- /*
- * Send IPI
- */
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
- | APIC_DM_INIT);
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- mdelay(10);
-
- Dprintk("Deasserting INIT.\n");
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
- /* Send IPI */
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- mb();
- atomic_set(&init_deasserted, 1);
-
- /*
- * Should we send STARTUP IPIs ?
- *
- * Determine this based on the APIC version.
- * If we don't have an integrated APIC, don't send the STARTUP IPIs.
- */
- if (APIC_INTEGRATED(apic_version[phys_apicid]))
- num_starts = 2;
- else
- num_starts = 0;
-
- /*
- * Paravirt / VMI wants a startup IPI hook here to set up the
- * target processor state.
- */
- startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
- (unsigned long) stack_start.sp);
-
- /*
- * Run STARTUP IPI loop.
- */
- Dprintk("#startup loops: %d.\n", num_starts);
-
- maxlvt = lapic_get_maxlvt();
-
- for (j = 1; j <= num_starts; j++) {
- Dprintk("Sending STARTUP #%d.\n",j);
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
- Dprintk("After apic_write.\n");
-
- /*
- * STARTUP IPI
- */
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
- /* Boot on the stack */
- /* Kick the second */
- apic_write_around(APIC_ICR, APIC_DM_STARTUP
- | (start_eip >> 12));
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(300);
-
- Dprintk("Startup point 1.\n");
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(200);
- /*
- * Due to the Pentium erratum 3AP.
- */
- if (maxlvt > 3) {
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- }
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- if (send_status || accept_status)
- break;
- }
- Dprintk("After Startup.\n");
-
- if (send_status)
- printk("APIC never delivered???\n");
- if (accept_status)
- printk("APIC delivery error (%lx).\n", accept_status);
-
- return (send_status | accept_status);
-}
-#endif /* WAKE_SECONDARY_VIA_INIT */
-
-extern cpumask_t cpu_initialized;
-
-struct create_idle {
- struct work_struct work;
- struct task_struct *idle;
- struct completion done;
- int cpu;
-};
-
-static void __cpuinit do_fork_idle(struct work_struct *work)
-{
- struct create_idle *c_idle =
- container_of(work, struct create_idle, work);
-
- c_idle->idle = fork_idle(c_idle->cpu);
- complete(&c_idle->done);
-}
-static int __cpuinit do_boot_cpu(int apicid, int cpu)
-/*
- * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
- * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
- * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu.
- */
-{
- unsigned long boot_error = 0;
- int timeout;
- unsigned long start_eip;
- unsigned short nmi_high = 0, nmi_low = 0;
- struct create_idle c_idle = {
- .cpu = cpu,
- .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
- };
- INIT_WORK(&c_idle.work, do_fork_idle);
-
- alternatives_smp_switch(1);
-
- c_idle.idle = get_idle_for_cpu(cpu);
-
- /*
- * We can't use kernel_thread since we must avoid to
- * reschedule the child.
- */
- if (c_idle.idle) {
- c_idle.idle->thread.sp = (unsigned long) (((struct pt_regs *)
- (THREAD_SIZE + task_stack_page(c_idle.idle))) - 1);
- init_idle(c_idle.idle, cpu);
- goto do_rest;
- }
-
- if (!keventd_up() || current_is_keventd())
- c_idle.work.func(&c_idle.work);
- else {
- schedule_work(&c_idle.work);
- wait_for_completion(&c_idle.done);
- }
-
- if (IS_ERR(c_idle.idle)) {
- printk(KERN_ERR "failed fork for CPU %d\n", cpu);
- return PTR_ERR(c_idle.idle);
- }
-
- set_idle_for_cpu(cpu, c_idle.idle);
-do_rest:
- per_cpu(current_task, cpu) = c_idle.idle;
- init_gdt(cpu);
- early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
-
- c_idle.idle->thread.ip = (unsigned long) start_secondary;
- /* start_eip had better be page-aligned! */
- start_eip = setup_trampoline();
-
- /* So we see what's up */
- printk("Booting processor %d/%d ip %lx\n", cpu, apicid, start_eip);
- /* Stack for startup_32 can be just as for start_secondary onwards */
- stack_start.sp = (void *) c_idle.idle->thread.sp;
-
- irq_ctx_init(cpu);
-
- /*
- * This grunge runs the startup process for
- * the targeted processor.
- */
-
- atomic_set(&init_deasserted, 0);
-
- Dprintk("Setting warm reset code and vector.\n");
-
- store_NMI_vector(&nmi_high, &nmi_low);
-
- smpboot_setup_warm_reset_vector(start_eip);
- /*
- * Be paranoid about clearing APIC errors.
- */
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
-
-
- /*
- * Starting actual IPI sequence...
- */
- boot_error = wakeup_secondary_cpu(apicid, start_eip);
-
- if (!boot_error) {
- /*
- * allow APs to start initializing.
- */
- Dprintk("Before Callout %d.\n", cpu);
- cpu_set(cpu, cpu_callout_map);
- Dprintk("After Callout %d.\n", cpu);
-
- /*
- * Wait 5s total for a response
- */
- for (timeout = 0; timeout < 50000; timeout++) {
- if (cpu_isset(cpu, cpu_callin_map))
- break; /* It has booted */
- udelay(100);
- }
-
- if (cpu_isset(cpu, cpu_callin_map)) {
- /* number CPUs logically, starting from 1 (BSP is 0) */
- Dprintk("OK.\n");
- printk("CPU%d: ", cpu);
- print_cpu_info(&cpu_data(cpu));
- Dprintk("CPU has booted.\n");
- } else {
- boot_error= 1;
- if (*((volatile unsigned char *)trampoline_base)
- == 0xA5)
- /* trampoline started but...? */
- printk("Stuck ??\n");
- else
- /* trampoline code not run */
- printk("Not responding.\n");
- inquire_remote_apic(apicid);
- }
- }
-
- if (boot_error) {
- /* Try to put things back the way they were before ... */
- unmap_cpu_to_logical_apicid(cpu);
- cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
- cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
- cpu_clear(cpu, cpu_possible_map);
- per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
- }
-
- /* mark "stuck" area as not stuck */
- *((volatile unsigned long *)trampoline_base) = 0;
-
- return boot_error;
-}
-
#ifdef CONFIG_HOTPLUG_CPU
void cpu_exit_clear(void)
{
@@ -774,65 +305,6 @@ void __init native_smp_prepare_boot_cpu(void)
__get_cpu_var(cpu_state) = CPU_ONLINE;
}

-int __cpuinit native_cpu_up(unsigned int cpu)
-{
- int apicid = cpu_present_to_apicid(cpu);
- unsigned long flags;
- int err;
-
- WARN_ON(irqs_disabled());
-
- Dprintk("++++++++++++++++++++=_---CPU UP %u\n", cpu);
-
- if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
- !physid_isset(apicid, phys_cpu_present_map)) {
- printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu);
- return -EINVAL;
- }
-
- /*
- * Already booted CPU?
- */
- if (cpu_isset(cpu, cpu_callin_map)) {
- Dprintk("do_boot_cpu %d Already started\n", cpu);
- return -ENOSYS;
- }
-
- /*
- * Save current MTRR state in case it was changed since early boot
- * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
- */
- mtrr_save_state();
-
- per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
-
- /* init low mem mapping */
- clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
- flush_tlb_all();
-
- err = do_boot_cpu(apicid, cpu);
- if (err < 0) {
- Dprintk("do_boot_cpu failed %d\n", err);
- return err;
- }
-
- /*
- * Check TSC synchronization with the AP (keep irqs disabled
- * while doing so):
- */
- local_irq_save(flags);
- check_tsc_sync_source(cpu);
- local_irq_restore(flags);
-
- while (!cpu_isset(cpu, cpu_online_map)) {
- cpu_relax();
- touch_nmi_watchdog();
- }
-
- return 0;
-}
-
extern void impress_friends(void);
extern void smp_checks(void);

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 420ae4a..71f13b1 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -71,119 +71,7 @@ int smp_threads_ready;
/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

-/*
- * Store all idle threads, this can be reused instead of creating
- * a new thread. Also avoids complicated thread destroy functionality
- * for idle threads.
- */
-#ifdef CONFIG_HOTPLUG_CPU
-/*
- * Needed only for CONFIG_HOTPLUG_CPU because __cpuinitdata is
- * removed after init for !CONFIG_HOTPLUG_CPU.
- */
-static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
-#define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x))
-#define set_idle_for_cpu(x,p) (per_cpu(idle_thread_array, x) = (p))
-#else
-struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
-#define get_idle_for_cpu(x) (idle_thread_array[(x)])
-#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p))
-#endif
-
-static atomic_t init_deasserted __cpuinitdata;
-
-#define smp_callin_clear_local_apic() do {} while (0)
-#define map_cpu_to_logical_apicid() do {} while (0)
-
-/*
- * Report back to the Boot Processor.
- * Running on AP.
- */
-void __cpuinit smp_callin(void)
-{
- int cpuid, phys_id;
- unsigned long timeout;
-
- /*
- * If waken up by an INIT in an 82489DX configuration
- * we may get here before an INIT-deassert IPI reaches
- * our local APIC. We have to wait for the IPI or we'll
- * lock up on an APIC access.
- */
- wait_for_init_deassert(&init_deasserted);
-
- /*
- * (This works even if the APIC is not enabled.)
- */
- phys_id = GET_APIC_ID(apic_read(APIC_ID));
- cpuid = smp_processor_id();
- if (cpu_isset(cpuid, cpu_callin_map)) {
- panic("smp_callin: phys CPU#%d, CPU#%d already present??\n",
- phys_id, cpuid);
- }
- Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
-
- /*
- * STARTUP IPIs are fragile beasts as they might sometimes
- * trigger some glue motherboard logic. Complete APIC bus
- * silence for 1 second, this overestimates the time the
- * boot CPU is spending to send the up to 2 STARTUP IPIs
- * by a factor of two. This should be enough.
- */
-
- /*
- * Waiting 2s total for startup (udelay is not yet working)
- */
- timeout = jiffies + 2*HZ;
- while (time_before(jiffies, timeout)) {
- /*
- * Has the boot CPU finished it's STARTUP sequence?
- */
- if (cpu_isset(cpuid, cpu_callout_map))
- break;
- cpu_relax();
- }
-
- if (!time_before(jiffies, timeout)) {
- panic("smp_callin: CPU%d started up but did not get a callout!\n",
- cpuid);
- }
-
- /*
- * the boot CPU has finished the init stage and is spinning
- * on callin_map until we finish. We are free to set up this
- * CPU, first the APIC. (this is probably redundant on most
- * boards)
- */
-
- Dprintk("CALLIN, before setup_local_APIC().\n");
- smp_callin_clear_local_apic();
- setup_local_APIC();
- end_local_APIC_setup();
- map_cpu_to_logical_apicid();
-
- /*
- * Get our bogomips.
- *
- * Need to enable IRQs because it can take longer and then
- * the NMI watchdog might kill us.
- */
- local_irq_enable();
- calibrate_delay();
- local_irq_disable();
- Dprintk("Stack at about %p\n",&cpuid);
-
- /*
- * Save our processor parameters
- */
- smp_store_cpu_info(cpuid);
-
- /*
- * Allow the master to continue.
- */
- cpu_set(cpuid, cpu_callin_map);
-}
-
+extern void smp_callin(void);
/*
* Setup code on secondary processor (after comming out of the trampoline)
*/
@@ -246,349 +134,6 @@ void __cpuinit start_secondary(void)
cpu_idle();
}

-extern volatile unsigned long init_rsp;
-extern void (*initial_code)(void);
-
-#ifdef APIC_DEBUG
-static void __inquire_remote_apic(int apicid)
-{
- unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
- char *names[] = { "ID", "VERSION", "SPIV" };
- int timeout;
- u32 status;
-
- printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);
-
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- printk(KERN_INFO "... APIC #%d %s: ", apicid, names[i]);
-
- /*
- * Wait for idle.
- */
- status = safe_apic_wait_icr_idle();
- if (status)
- printk(KERN_CONT
- "a previous APIC delivery may have failed\n");
-
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
-
- timeout = 0;
- do {
- udelay(100);
- status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
- } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
-
- switch (status) {
- case APIC_ICR_RR_VALID:
- status = apic_read(APIC_RRR);
- printk(KERN_CONT "%08x\n", status);
- break;
- default:
- printk(KERN_CONT "failed\n");
- }
- }
-}
-#endif
-
-/*
- * Kick the secondary to wake up.
- */
-static int __cpuinit wakeup_secondary_cpu(int phys_apicid,
- unsigned int start_rip)
-{
- unsigned long send_status, accept_status = 0;
- int maxlvt, num_starts, j;
-
- /*
- * Be paranoid about clearing APIC errors.
- */
- if (APIC_INTEGRATED(apic_version[phys_apicid])) {
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
- }
-
- Dprintk("Asserting INIT.\n");
-
- /*
- * Turn INIT on target chip
- */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
- /*
- * Send IPI
- */
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
- | APIC_DM_INIT);
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- mdelay(10);
-
- Dprintk("Deasserting INIT.\n");
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
- /* Send IPI */
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- mb();
- atomic_set(&init_deasserted, 1);
-
- if (APIC_INTEGRATED(apic_version[phys_apicid]))
- num_starts = 2;
- else
- num_starts = 0;
-
- /*
- * Paravirt / VMI wants a startup IPI hook here to set up the
- * target processor state.
- */
- startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
- (unsigned long) init_rsp);
-
-
- /*
- * Run STARTUP IPI loop.
- */
- Dprintk("#startup loops: %d.\n", num_starts);
-
- maxlvt = lapic_get_maxlvt();
-
- for (j = 1; j <= num_starts; j++) {
- Dprintk("Sending STARTUP #%d.\n",j);
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
- Dprintk("After apic_write.\n");
-
- /*
- * STARTUP IPI
- */
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
- /* Boot on the stack */
- /* Kick the second */
- apic_write_around(APIC_ICR, APIC_DM_STARTUP | (start_rip>>12));
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(300);
-
- Dprintk("Startup point 1.\n");
-
- Dprintk("Waiting for send to finish...\n");
- send_status = safe_apic_wait_icr_idle();
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(200);
- /*
- * Due to the Pentium erratum 3AP.
- */
- if (maxlvt > 3) {
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- }
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- if (send_status || accept_status)
- break;
- }
- Dprintk("After Startup.\n");
-
- if (send_status)
- printk(KERN_ERR "APIC never delivered???\n");
- if (accept_status)
- printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
-
- return (send_status | accept_status);
-}
-
-struct create_idle {
- struct work_struct work;
- struct task_struct *idle;
- struct completion done;
- int cpu;
-};
-
-static void __cpuinit do_fork_idle(struct work_struct *work)
-{
- struct create_idle *c_idle =
- container_of(work, struct create_idle, work);
-
- c_idle->idle = fork_idle(c_idle->cpu);
- complete(&c_idle->done);
-}
-
-/*
- * Boot one CPU.
- */
-static int __cpuinit do_boot_cpu(int cpu, int apicid)
-{
- unsigned long boot_error = 0;
- int timeout;
- unsigned long start_rip;
- struct create_idle c_idle = {
- .cpu = cpu,
- .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
- };
- INIT_WORK(&c_idle.work, do_fork_idle);
-
- /* allocate memory for gdts of secondary cpus. Hotplug is considered */
- if (!cpu_gdt_descr[cpu].address &&
- !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) {
- printk(KERN_ERR "Failed to allocate GDT for CPU %d\n", cpu);
- return -1;
- }
-
- /* Allocate node local memory for AP pdas */
- if (cpu_pda(cpu) == &boot_cpu_pda[cpu]) {
- struct x8664_pda *newpda, *pda;
- int node = cpu_to_node(cpu);
- pda = cpu_pda(cpu);
- newpda = kmalloc_node(sizeof (struct x8664_pda), GFP_ATOMIC,
- node);
- if (newpda) {
- memcpy(newpda, pda, sizeof (struct x8664_pda));
- cpu_pda(cpu) = newpda;
- } else
- printk(KERN_ERR
- "Could not allocate node local PDA for CPU %d on node %d\n",
- cpu, node);
- }
-
- alternatives_smp_switch(1);
-
- c_idle.idle = get_idle_for_cpu(cpu);
-
- if (c_idle.idle) {
- c_idle.idle->thread.sp = (unsigned long) (((struct pt_regs *)
- (THREAD_SIZE + task_stack_page(c_idle.idle))) - 1);
- init_idle(c_idle.idle, cpu);
- goto do_rest;
- }
-
- /*
- * During cold boot process, keventd thread is not spun up yet.
- * When we do cpu hot-add, we create idle threads on the fly, we should
- * not acquire any attributes from the calling context. Hence the clean
- * way to create kernel_threads() is to do that from keventd().
- * We do the current_is_keventd() due to the fact that ACPI notifier
- * was also queuing to keventd() and when the caller is already running
- * in context of keventd(), we would end up with locking up the keventd
- * thread.
- */
- if (!keventd_up() || current_is_keventd())
- c_idle.work.func(&c_idle.work);
- else {
- schedule_work(&c_idle.work);
- wait_for_completion(&c_idle.done);
- }
-
- if (IS_ERR(c_idle.idle)) {
- printk("failed fork for CPU %d\n", cpu);
- return PTR_ERR(c_idle.idle);
- }
-
- set_idle_for_cpu(cpu, c_idle.idle);
-
-do_rest:
-
- cpu_pda(cpu)->pcurrent = c_idle.idle;
-
- start_rip = setup_trampoline();
-
- init_rsp = c_idle.idle->thread.sp;
- load_sp0(&per_cpu(init_tss, cpu), &c_idle.idle->thread);
- initial_code = start_secondary;
- clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
-
- printk(KERN_INFO "Booting processor %d/%d APIC 0x%x\n", cpu,
- cpus_weight(cpu_present_map),
- apicid);
-
- /*
- * This grunge runs the startup process for
- * the targeted processor.
- */
-
- atomic_set(&init_deasserted, 0);
-
- Dprintk("Setting warm reset code and vector.\n");
-
- smpboot_setup_warm_reset_vector(start_rip);
- /*
- * Be paranoid about clearing APIC errors.
- */
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
-
- /*
- * Starting actual IPI sequence...
- */
- boot_error = wakeup_secondary_cpu(apicid, start_rip);
-
- if (!boot_error) {
- /*
- * allow APs to start initializing.
- */
- Dprintk("Before Callout %d.\n", cpu);
- cpu_set(cpu, cpu_callout_map);
- Dprintk("After Callout %d.\n", cpu);
-
- /*
- * Wait 5s total for a response
- */
- for (timeout = 0; timeout < 50000; timeout++) {
- if (cpu_isset(cpu, cpu_callin_map))
- break; /* It has booted */
- udelay(100);
- }
-
- if (cpu_isset(cpu, cpu_callin_map)) {
- /* number CPUs logically, starting from 1 (BSP is 0) */
- Dprintk("CPU has booted.\n");
- printk(KERN_INFO "CPU%d: ", cpu);
- print_cpu_info(&cpu_data(cpu));
- } else {
- boot_error = 1;
- if (*((volatile unsigned char *)trampoline_base)
- == 0xA5)
- /* trampoline started but...? */
- printk("Stuck ??\n");
- else
- /* trampoline code not run */
- printk("Not responding.\n");
-#ifdef APIC_DEBUG
- inquire_remote_apic(apicid);
-#endif
- }
- }
- if (boot_error) {
- cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
- clear_bit(cpu, (unsigned long *)&cpu_initialized); /* was set by cpu_init() */
- clear_node_cpumask(cpu); /* was set by numa_add_cpu */
- cpu_clear(cpu, cpu_present_map);
- cpu_clear(cpu, cpu_possible_map);
- per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
- }
-
- /* mark "stuck" area as not stuck */
- *((volatile unsigned long *)trampoline_base) = 0;
-
- return boot_error;
-}
-
cycles_t cacheflush_time;
unsigned long cache_decay_ticks;

@@ -745,64 +290,6 @@ void __init native_smp_prepare_boot_cpu(void)
per_cpu(cpu_state, me) = CPU_ONLINE;
}

-/*
- * Entry point to boot a CPU.
- */
-int __cpuinit native_cpu_up(unsigned int cpu)
-{
- int apicid = cpu_present_to_apicid(cpu);
- unsigned long flags;
- int err;
-
- WARN_ON(irqs_disabled());
-
- Dprintk("++++++++++++++++++++=_---CPU UP %u\n", cpu);
-
- if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
- !physid_isset(apicid, phys_cpu_present_map)) {
- printk("__cpu_up: bad cpu %d\n", cpu);
- return -EINVAL;
- }
-
- /*
- * Already booted CPU?
- */
- if (cpu_isset(cpu, cpu_callin_map)) {
- Dprintk("do_boot_cpu %d Already started\n", cpu);
- return -ENOSYS;
- }
-
- /*
- * Save current MTRR state in case it was changed since early boot
- * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
- */
- mtrr_save_state();
-
- per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
- /* Boot it! */
- err = do_boot_cpu(cpu, apicid);
- if (err < 0) {
- Dprintk("do_boot_cpu failed %d\n", err);
- return err;
- }
-
- /* Unleash the CPU! */
- Dprintk("waiting for cpu %d\n", cpu);
-
- /*
- * Make sure and check TSC sync:
- */
- local_irq_save(flags);
- check_tsc_sync_source(cpu);
- local_irq_restore(flags);
-
- while (!cpu_isset(cpu, cpu_online_map))
- cpu_relax();
- err = 0;
-
- return err;
-}
-
extern void impress_friends(void);
extern void smp_checks(void);

diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 2ad2f4f..ef26911 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -9,6 +9,7 @@ extern cpumask_t cpu_callout_map;

extern int smp_num_siblings;
extern unsigned int num_processors;
+extern cpumask_t cpu_initialized;

extern u16 x86_cpu_to_apicid_init[];
extern u16 x86_bios_cpu_apicid_init[];
@@ -34,6 +35,8 @@ extern struct {
unsigned short ss;
} stack_start;

+extern unsigned long init_rsp;
+extern unsigned long initial_code;

struct smp_ops {
void (*smp_prepare_boot_cpu)(void);
--
1.5.0.6

2008-03-19 20:33:43

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 11/79] [PATCH] always enable irqs when entering idle

From: Glauber Costa <[email protected]>

This matches x86_64 behaviour, which is a superior one IMHO

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/process_32.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index ec05fb7..08c41ed 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -127,6 +127,7 @@ void default_idle(void)
local_irq_enable();
current_thread_info()->status |= TS_POLLING;
} else {
+ local_irq_enable();
/* loop is done by the caller */
cpu_relax();
}
@@ -142,6 +143,7 @@ EXPORT_SYMBOL(default_idle);
*/
static void poll_idle(void)
{
+ local_irq_enable();
cpu_relax();
}

@@ -248,8 +250,11 @@ void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
__monitor((void *)&current_thread_info()->flags, 0, 0);
smp_mb();
if (!need_resched())
- __mwait(ax, cx);
- }
+ __sti_mwait(ax, cx);
+ else
+ local_irq_enable();
+ } else
+ local_irq_enable();
}

/* Default MONITOR/MWAIT with no hints, used for default C1 state */
--
1.5.0.6

2008-03-19 20:27:51

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 41/79] [PATCH] unify nmi_32.h and nmi_64.h

From: Glauber Costa <[email protected]>

Two more files goes away. nmi_64.h and nmi_32.h gives birth
to nmi.h

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/nmi_32.c | 2 +-
include/asm-x86/nmi.h | 92 ++++++++++++++++++++++++++++++++++++++++++++-
include/asm-x86/nmi_32.h | 61 ------------------------------
include/asm-x86/nmi_64.h | 88 --------------------------------------------
4 files changed, 90 insertions(+), 153 deletions(-)
delete mode 100644 include/asm-x86/nmi_32.h
delete mode 100644 include/asm-x86/nmi_64.h

diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c
index aa6800f..daea273 100644
--- a/arch/x86/kernel/nmi_32.c
+++ b/arch/x86/kernel/nmi_32.c
@@ -67,7 +67,7 @@ static __init void nmi_cpu_busy(void *data)
}
#endif

-static int __init check_nmi_watchdog(void)
+int __init check_nmi_watchdog(void)
{
unsigned int *prev_nmi_count;
int cpu;
diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h
index 53ccac1..2b94199 100644
--- a/include/asm-x86/nmi.h
+++ b/include/asm-x86/nmi.h
@@ -1,5 +1,91 @@
-#ifdef CONFIG_X86_32
-# include "nmi_32.h"
+#ifndef _ASM_X86_NMI_H_
+#define _ASM_X86_NMI_H_
+
+#include <linux/pm.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#ifdef ARCH_HAS_NMI_WATCHDOG
+
+/**
+ * do_nmi_callback
+ *
+ * Check to see if a callback exists and execute it. Return 1
+ * if the handler exists and was handled successfully.
+ */
+int do_nmi_callback(struct pt_regs *regs, int cpu);
+
+#ifdef CONFIG_PM
+
+/** Replace the PM callback routine for NMI. */
+struct pm_dev *set_nmi_pm_callback(pm_callback callback);
+
+/** Unset the PM callback routine back to the default. */
+void unset_nmi_pm_callback(struct pm_dev *dev);
+
#else
-# include "nmi_64.h"
+
+static inline struct pm_dev *set_nmi_pm_callback(pm_callback callback)
+{
+ return 0;
+}
+
+static inline void unset_nmi_pm_callback(struct pm_dev *dev)
+{
+}
+
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_X86_64
+extern void default_do_nmi(struct pt_regs *);
+extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
+#endif
+
+extern int check_nmi_watchdog(void);
+extern int nmi_watchdog_enabled;
+extern int unknown_nmi_panic;
+extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
+extern int avail_to_resrv_perfctr_nmi(unsigned int);
+extern int reserve_perfctr_nmi(unsigned int);
+extern void release_perfctr_nmi(unsigned int);
+extern int reserve_evntsel_nmi(unsigned int);
+extern void release_evntsel_nmi(unsigned int);
+extern void nmi_watchdog_default(void);
+
+extern void setup_apic_nmi_watchdog(void *);
+extern void stop_apic_nmi_watchdog(void *);
+extern void disable_timer_nmi_watchdog(void);
+extern void enable_timer_nmi_watchdog(void);
+extern int nmi_watchdog_tick(struct pt_regs *regs, unsigned reason);
+
+extern atomic_t nmi_active;
+extern unsigned int nmi_watchdog;
+#define NMI_DISABLED -1
+#define NMI_NONE 0
+#define NMI_IO_APIC 1
+#define NMI_LOCAL_APIC 2
+#define NMI_INVALID 3
+#define NMI_DEFAULT NMI_DISABLED
+
+struct ctl_table;
+struct file;
+extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
+ void __user *, size_t *, loff_t *);
+extern int unknown_nmi_panic;
+
+void __trigger_all_cpu_backtrace(void);
+#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
+
+#endif
+
+void lapic_watchdog_stop(void);
+int lapic_watchdog_init(unsigned nmi_hz);
+int lapic_wd_event(unsigned nmi_hz);
+unsigned lapic_adjust_nmi_hz(unsigned hz);
+int lapic_watchdog_ok(void);
+void disable_lapic_nmi_watchdog(void);
+void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
+
#endif
diff --git a/include/asm-x86/nmi_32.h b/include/asm-x86/nmi_32.h
deleted file mode 100644
index 7206c7e..0000000
--- a/include/asm-x86/nmi_32.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ASM_NMI_H
-#define ASM_NMI_H
-
-#include <linux/pm.h>
-#include <asm/irq.h>
-
-#ifdef ARCH_HAS_NMI_WATCHDOG
-
-/**
- * do_nmi_callback
- *
- * Check to see if a callback exists and execute it. Return 1
- * if the handler exists and was handled successfully.
- */
-int do_nmi_callback(struct pt_regs *regs, int cpu);
-
-extern int nmi_watchdog_enabled;
-extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
-extern int avail_to_resrv_perfctr_nmi(unsigned int);
-extern int reserve_perfctr_nmi(unsigned int);
-extern void release_perfctr_nmi(unsigned int);
-extern int reserve_evntsel_nmi(unsigned int);
-extern void release_evntsel_nmi(unsigned int);
-
-extern void setup_apic_nmi_watchdog (void *);
-extern void stop_apic_nmi_watchdog (void *);
-extern void disable_timer_nmi_watchdog(void);
-extern void enable_timer_nmi_watchdog(void);
-extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
-
-extern atomic_t nmi_active;
-extern unsigned int nmi_watchdog;
-#define NMI_DISABLED -1
-#define NMI_NONE 0
-#define NMI_IO_APIC 1
-#define NMI_LOCAL_APIC 2
-#define NMI_INVALID 3
-#define NMI_DEFAULT NMI_DISABLED
-
-struct ctl_table;
-struct file;
-extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
- void __user *, size_t *, loff_t *);
-extern int unknown_nmi_panic;
-
-void __trigger_all_cpu_backtrace(void);
-#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
-
-#endif
-
-void lapic_watchdog_stop(void);
-int lapic_watchdog_init(unsigned nmi_hz);
-int lapic_wd_event(unsigned nmi_hz);
-unsigned lapic_adjust_nmi_hz(unsigned hz);
-int lapic_watchdog_ok(void);
-void disable_lapic_nmi_watchdog(void);
-void enable_lapic_nmi_watchdog(void);
-void stop_nmi(void);
-void restart_nmi(void);
-
-#endif /* ASM_NMI_H */
diff --git a/include/asm-x86/nmi_64.h b/include/asm-x86/nmi_64.h
deleted file mode 100644
index 94a5b19..0000000
--- a/include/asm-x86/nmi_64.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef ASM_NMI_H
-#define ASM_NMI_H
-
-#include <linux/pm.h>
-#include <asm/io.h>
-
-/**
- * do_nmi_callback
- *
- * Check to see if a callback exists and execute it. Return 1
- * if the handler exists and was handled successfully.
- */
-int do_nmi_callback(struct pt_regs *regs, int cpu);
-
-#ifdef CONFIG_PM
-
-/** Replace the PM callback routine for NMI. */
-struct pm_dev * set_nmi_pm_callback(pm_callback callback);
-
-/** Unset the PM callback routine back to the default. */
-void unset_nmi_pm_callback(struct pm_dev * dev);
-
-#else
-
-static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback)
-{
- return 0;
-}
-
-static inline void unset_nmi_pm_callback(struct pm_dev * dev)
-{
-}
-
-#endif /* CONFIG_PM */
-
-extern void default_do_nmi(struct pt_regs *);
-extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
-
-extern int unknown_nmi_panic;
-extern int nmi_watchdog_enabled;
-
-extern int check_nmi_watchdog(void);
-extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
-extern int avail_to_resrv_perfctr_nmi(unsigned int);
-extern int reserve_perfctr_nmi(unsigned int);
-extern void release_perfctr_nmi(unsigned int);
-extern int reserve_evntsel_nmi(unsigned int);
-extern void release_evntsel_nmi(unsigned int);
-
-extern void setup_apic_nmi_watchdog (void *);
-extern void stop_apic_nmi_watchdog (void *);
-extern void disable_timer_nmi_watchdog(void);
-extern void enable_timer_nmi_watchdog(void);
-extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
-
-extern void nmi_watchdog_default(void);
-
-extern atomic_t nmi_active;
-extern unsigned int nmi_watchdog;
-#define NMI_DISABLED -1
-#define NMI_NONE 0
-#define NMI_IO_APIC 1
-#define NMI_LOCAL_APIC 2
-#define NMI_INVALID 3
-#define NMI_DEFAULT NMI_DISABLED
-
-struct ctl_table;
-struct file;
-extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
- void __user *, size_t *, loff_t *);
-
-extern int unknown_nmi_panic;
-
-void __trigger_all_cpu_backtrace(void);
-#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
-
-
-void lapic_watchdog_stop(void);
-int lapic_watchdog_init(unsigned nmi_hz);
-int lapic_wd_event(unsigned nmi_hz);
-unsigned lapic_adjust_nmi_hz(unsigned hz);
-int lapic_watchdog_ok(void);
-void disable_lapic_nmi_watchdog(void);
-void enable_lapic_nmi_watchdog(void);
-void stop_nmi(void);
-void restart_nmi(void);
-
-#endif /* ASM_NMI_H */
--
1.5.0.6

2008-03-19 20:20:01

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 66/79] [PATCH] merge smp_prepare_boot_cpu

From: Glauber Costa <[email protected]>

it is practically the same between arches now, so it is
moved to smpboot.c. Minor differences (gdt initialization)
live inside an ifdef

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 18 ++++++++++++++++++
arch/x86/kernel/smpboot_32.c | 14 --------------
arch/x86/kernel/smpboot_64.c | 14 --------------
3 files changed, 18 insertions(+), 28 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index a36ae27..b214d8d 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -24,6 +24,9 @@
#include <mach_wakecpu.h>
#include <smpboot_hooks.h>

+/* State of each CPU */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
/* Store all idle threads, this can be reused instead of creating
* a new thread. Also avoids complicated thread destroy functionality
* for idle threads.
@@ -999,6 +1002,21 @@ int __cpuinit native_cpu_up(unsigned int cpu)
return 0;
}

+/*
+ * Early setup to make printk work.
+ */
+void __init native_smp_prepare_boot_cpu(void)
+{
+ int me = smp_processor_id();
+#ifdef CONFIG_X86_32
+ init_gdt(me);
+ switch_to_new_gdt();
+#endif
+ /* already set me in cpu_online_map in boot_cpu_init() */
+ cpu_set(me, cpu_callout_map);
+ per_cpu(cpu_state, me) = CPU_ONLINE;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
void remove_siblinginfo(int cpu)
{
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 77b045c..5d27b1d 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -77,9 +77,6 @@ u8 apicid_2_node[MAX_APICID];
extern void map_cpu_to_logical_apicid(void);
extern void unmap_cpu_to_logical_apicid(int cpu);

-/* State of each CPU. */
-DEFINE_PER_CPU(int, cpu_state) = { 0 };
-
#ifdef CONFIG_HOTPLUG_CPU
void cpu_exit_clear(void)
{
@@ -219,17 +216,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
smp_boot_cpus(max_cpus);
}

-void __init native_smp_prepare_boot_cpu(void)
-{
- unsigned int cpu = smp_processor_id();
-
- init_gdt(cpu);
- switch_to_new_gdt();
-
- cpu_set(cpu, cpu_callout_map);
- __get_cpu_var(cpu_state) = CPU_ONLINE;
-}
-
extern void impress_friends(void);
extern void smp_checks(void);

diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 60cd8cf..f77299b 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -68,9 +68,6 @@
/* Set when the idlers are all forked */
int smp_threads_ready;

-/* State of each CPU */
-DEFINE_PER_CPU(int, cpu_state) = { 0 };
-
cycles_t cacheflush_time;
unsigned long cache_decay_ticks;

@@ -216,17 +213,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
print_cpu_info(&cpu_data(0));
}

-/*
- * Early setup to make printk work.
- */
-void __init native_smp_prepare_boot_cpu(void)
-{
- int me = smp_processor_id();
- /* already set me in cpu_online_map in boot_cpu_init() */
- cpu_set(me, cpu_callout_map);
- per_cpu(cpu_state, me) = CPU_ONLINE;
-}
-
extern void impress_friends(void);
extern void smp_checks(void);

--
1.5.0.6

2008-03-19 20:16:24

by Glauber Costa

[permalink] [raw]
Subject: [PATCH 33/79] [PATCH] do smp tainting checks in a separate function

From: Glauber Costa <[email protected]>

It will ease integration for x86_64

Signed-off-by: Glauber Costa <[email protected]>
---
arch/x86/kernel/smpboot.c | 21 +++++++++++++++++++--
arch/x86/kernel/smpboot_32.c | 20 ++------------------
2 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 02427d1..ddb94ef 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -45,10 +45,8 @@ unsigned char *trampoline_base = __va(SMP_TRAMPOLINE_BASE);
/* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map;

-#ifdef CONFIG_X86_32
/* Set if we find a B stepping CPU */
int __cpuinitdata smp_b_stepping;
-#endif

static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
{
@@ -105,6 +103,25 @@ valid_k7:
#endif
}

+void smp_checks(void)
+{
+ if (smp_b_stepping)
+ printk(KERN_WARNING "WARNING: SMP operation may be unreliable"
+ "with B stepping processors.\n");
+
+ /*
+ * Don't taint if we are running SMP kernel on a single non-MP
+ * approved Athlon
+ */
+ if (tainted & TAINT_UNSAFE_SMP) {
+ if (cpus_weight(cpu_present_map))
+ printk(KERN_INFO "WARNING: This combination of AMD"
+ "processors is not suitable for SMP.\n");
+ else
+ tainted &= ~TAINT_UNSAFE_SMP;
+ }
+}
+
/*
* The bootstrap kernel entry code has set these up. Save them for
* a given CPU
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 34493f8..361851c 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -59,8 +59,6 @@
#include <asm/vmi.h>
#include <asm/mtrr.h>

-extern int smp_b_stepping;
-
static cpumask_t smp_commenced_mask;

/* which logical CPU number maps to which CPU (physical APIC ID) */
@@ -791,6 +789,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
}

extern void impress_friends(void);
+extern void smp_checks(void);
/*
* Cycle through the processors sending APIC IPIs to boot each.
*/
@@ -865,22 +864,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

impress_friends();

- if (smp_b_stepping)
- printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
-
- /*
- * Don't taint if we are running SMP kernel on a single non-MP
- * approved Athlon
- */
- if (tainted & TAINT_UNSAFE_SMP) {
- if (cpus_weight(cpu_present_map))
- printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n");
- else
- tainted &= ~TAINT_UNSAFE_SMP;
- }
-
- Dprintk("Boot done.\n");
-
+ smp_checks();
/*
* construct cpu_sibling_map, so that we can tell sibling CPUs
* efficiently.
--
1.5.0.6

2008-03-19 22:43:18

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration


the small fix below was needed - it is possible to build ACPI on 32-bit
with APIC support disabled. Otherwise it's looking good in my testing.

Ingo

-----------------
Subject: x86: smp unify2 include mach apic h in smpboot 64 c and smpboot c fix
From: Ingo Molnar <[email protected]>
Date: Wed Mar 19 19:25:58 CET 2008

Signed-off-by: Ingo Molnar <[email protected]>
---
arch/x86/kernel/acpi/boot.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

Index: linux-x86.q/arch/x86/kernel/acpi/boot.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/acpi/boot.c
+++ linux-x86.q/arch/x86/kernel/acpi/boot.c
@@ -40,7 +40,9 @@
#include <asm/io.h>
#include <asm/mpspec.h>

-#include <mach_apic.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+# include <mach_apic.h>
+#endif

static int __initdata acpi_force = 0;

2008-03-19 22:47:06

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration


* Glauber de Oliveira Costa <[email protected]> wrote:

> Testing and bisectability:
>
> The end result was tested in all my hardware (which includes qemu ;-).
> It does not mean it will boot _your_ hardware, but I did my best ;-)
>
> The tree at least compiles in more than 20 randconfigs (for each of
> x86_64 and i386) For i386, each of the subarchitectures was compiled
> at least once. (By compile, I obviously mean, every patch,
> individually)

very nice work! I'll pick it up - and i'm not too worried about
breakages because at 80 patches granularity any problem should be
identifiable in a very finegrained way.

Ingo

2008-03-20 02:18:24

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

On Wed, Mar 19, 2008 at 10:35 AM, Ingo Molnar <[email protected]> wrote:
>
> * Glauber de Oliveira Costa <[email protected]> wrote:
>
> > Testing and bisectability:
> >
> > The end result was tested in all my hardware (which includes qemu ;-).
> > It does not mean it will boot _your_ hardware, but I did my best ;-)
> >
> > The tree at least compiles in more than 20 randconfigs (for each of
> > x86_64 and i386) For i386, each of the subarchitectures was compiled
> > at least once. (By compile, I obviously mean, every patch,
> > individually)
>
> very nice work! I'll pick it up - and i'm not too worried about
> breakages because at 80 patches granularity any problem should be
> identifiable in a very finegrained way.
>

it broke 4 sockets quad core above with 64 bit

Booting processor 11/15 ip 6000
Initializing CPU#11
masked ExtINT on CPU#11
Calibrating delay using timer specific routine.. 4589.46 BogoMIPS (lpj=9178934)
CPU: L1 I Cache: 64K (64 bytes/line), D cache 64K (64 bytes/line)
CPU: L2 Cache: 512K (64 bytes/line)
CPU 11/f -> Node 2
CPU: Physical Processor ID: 2
CPU: Processor Core ID: 3
CPU11: Quad-Core AMD Opteron(tm) Processor 8356 stepping 03
checking TSC synchronization [CPU#0 -> CPU#11]: passed.
Booting processor 12/16 ip 6000

looks like local apic id up 4 bit is masked out. so can not start 0x10
above any more.

YH

2008-03-20 03:00:36

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

On Wed, Mar 19, 2008 at 7:18 PM, Yinghai Lu <[email protected]> wrote:
> On Wed, Mar 19, 2008 at 10:35 AM, Ingo Molnar <[email protected]> wrote:
> >
> > * Glauber de Oliveira Costa <[email protected]> wrote:
> >
> > > Testing and bisectability:
> > >
> > > The end result was tested in all my hardware (which includes qemu ;-).
> > > It does not mean it will boot _your_ hardware, but I did my best ;-)
> > >
> > > The tree at least compiles in more than 20 randconfigs (for each of
> > > x86_64 and i386) For i386, each of the subarchitectures was compiled
> > > at least once. (By compile, I obviously mean, every patch,
> > > individually)
> >
> > very nice work! I'll pick it up - and i'm not too worried about
> > breakages because at 80 patches granularity any problem should be
> > identifiable in a very finegrained way.
> >
>
> it broke 4 sockets quad core above with 64 bit
>
> Booting processor 11/15 ip 6000
> Initializing CPU#11
> masked ExtINT on CPU#11
> Calibrating delay using timer specific routine.. 4589.46 BogoMIPS (lpj=9178934)
> CPU: L1 I Cache: 64K (64 bytes/line), D cache 64K (64 bytes/line)
> CPU: L2 Cache: 512K (64 bytes/line)
> CPU 11/f -> Node 2
> CPU: Physical Processor ID: 2
> CPU: Processor Core ID: 3
> CPU11: Quad-Core AMD Opteron(tm) Processor 8356 stepping 03
> checking TSC synchronization [CPU#0 -> CPU#11]: passed.
> Booting processor 12/16 ip 6000
>
> looks like local apic id up 4 bit is masked out. so can not start 0x10
> above any more.

in wakeup_secondary_via_INIT
before the patchsets
64 bit code:

/*
* Send IPI
*/
apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
| APIC_DM_INIT);


after patchset

/* Boot on the stack */
/* Kick the second */
apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);

So that is wrong! esp for system has ext apic id that is has 8 bits
instead of 4 bits.

YH

2008-03-20 03:32:37

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

On Wed, Mar 19, 2008 at 8:00 PM, Yinghai Lu <[email protected]> wrote:
>
> On Wed, Mar 19, 2008 at 7:18 PM, Yinghai Lu <[email protected]> wrote:
> > On Wed, Mar 19, 2008 at 10:35 AM, Ingo Molnar <[email protected]> wrote:
> > >
> > > * Glauber de Oliveira Costa <[email protected]> wrote:
> > >
> > > > Testing and bisectability:
> > > >
> > > > The end result was tested in all my hardware (which includes qemu ;-).
> > > > It does not mean it will boot _your_ hardware, but I did my best ;-)
> > > >
> > > > The tree at least compiles in more than 20 randconfigs (for each of
> > > > x86_64 and i386) For i386, each of the subarchitectures was compiled
> > > > at least once. (By compile, I obviously mean, every patch,
> > > > individually)
> > >
> > > very nice work! I'll pick it up - and i'm not too worried about
> > > breakages because at 80 patches granularity any problem should be
> > > identifiable in a very finegrained way.
> > >
> >
> > it broke 4 sockets quad core above with 64 bit
> >
> > Booting processor 11/15 ip 6000
> > Initializing CPU#11
> > masked ExtINT on CPU#11
> > Calibrating delay using timer specific routine.. 4589.46 BogoMIPS (lpj=9178934)
> > CPU: L1 I Cache: 64K (64 bytes/line), D cache 64K (64 bytes/line)
> > CPU: L2 Cache: 512K (64 bytes/line)
> > CPU 11/f -> Node 2
> > CPU: Physical Processor ID: 2
> > CPU: Processor Core ID: 3
> > CPU11: Quad-Core AMD Opteron(tm) Processor 8356 stepping 03
> > checking TSC synchronization [CPU#0 -> CPU#11]: passed.
> > Booting processor 12/16 ip 6000
> >
> > looks like local apic id up 4 bit is masked out. so can not start 0x10
> > above any more.
>
> in wakeup_secondary_via_INIT
> before the patchsets
> 64 bit code:
>
> /*
> * Send IPI
> */
> apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
> | APIC_DM_INIT);
>
>
> after patchset
>
> /* Boot on the stack */
> /* Kick the second */
> apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
>
> So that is wrong! esp for system has ext apic id that is has 8 bits
> instead of 4 bits.
>

it seems there is two wakeup_secondary_cpu. one for NMI and one INIT.

but should have

#define WAKE_SECONDARY_VIA_INIT

for x86_64

but after

#ifdef CONFIG_X86_64
#undef WAKE_SECONDARY_VIA_NMI
#define WAKE_SECONDARY_VIA_INIT
#endif

it still doesn't work.

YH

2008-03-20 04:44:56

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

Yinghai Lu wrote:
> On Wed, Mar 19, 2008 at 8:00 PM, Yinghai Lu <[email protected]> wrote:
>> On Wed, Mar 19, 2008 at 7:18 PM, Yinghai Lu <[email protected]> wrote:
>> > On Wed, Mar 19, 2008 at 10:35 AM, Ingo Molnar <[email protected]> wrote:
>> > >
>> > > * Glauber de Oliveira Costa <[email protected]> wrote:
>> > >
>> > > > Testing and bisectability:
>> > > >
>> > > > The end result was tested in all my hardware (which includes qemu ;-).
>> > > > It does not mean it will boot _your_ hardware, but I did my best ;-)
>> > > >
>> > > > The tree at least compiles in more than 20 randconfigs (for each of
>> > > > x86_64 and i386) For i386, each of the subarchitectures was compiled
>> > > > at least once. (By compile, I obviously mean, every patch,
>> > > > individually)
>> > >
>> > > very nice work! I'll pick it up - and i'm not too worried about
>> > > breakages because at 80 patches granularity any problem should be
>> > > identifiable in a very finegrained way.
>> > >
>> >
>> > it broke 4 sockets quad core above with 64 bit
>> >
>> > Booting processor 11/15 ip 6000
>> > Initializing CPU#11
>> > masked ExtINT on CPU#11
>> > Calibrating delay using timer specific routine.. 4589.46 BogoMIPS (lpj=9178934)
>> > CPU: L1 I Cache: 64K (64 bytes/line), D cache 64K (64 bytes/line)
>> > CPU: L2 Cache: 512K (64 bytes/line)
>> > CPU 11/f -> Node 2
>> > CPU: Physical Processor ID: 2
>> > CPU: Processor Core ID: 3
>> > CPU11: Quad-Core AMD Opteron(tm) Processor 8356 stepping 03
>> > checking TSC synchronization [CPU#0 -> CPU#11]: passed.
>> > Booting processor 12/16 ip 6000
>> >
>> > looks like local apic id up 4 bit is masked out. so can not start 0x10
>> > above any more.
>>
>> in wakeup_secondary_via_INIT
>> before the patchsets
>> 64 bit code:
>>
>> /*
>> * Send IPI
>> */
>> apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
>> | APIC_DM_INIT);
>>
>>
>> after patchset
>>
>> /* Boot on the stack */
>> /* Kick the second */
>> apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
>>
>> So that is wrong! esp for system has ext apic id that is has 8 bits
>> instead of 4 bits.
>>
>
> it seems there is two wakeup_secondary_cpu. one for NMI and one INIT.
>
> but should have
>
> #define WAKE_SECONDARY_VIA_INIT
>
> for x86_64
>
> but after
>
> #ifdef CONFIG_X86_64
> #undef WAKE_SECONDARY_VIA_NMI
> #define WAKE_SECONDARY_VIA_INIT
> #endif
>
> it still doesn't work.
>
> YH
Thanks for the testing Yinghai. I'll take a deeper look as soon as I
can. The two routines are provided, since i386 numa-q inits the startup
sequence through NMIs. The _VIA_INIT is already defined in x86_64 in the
mach-default/ headers.

What happens exactly? Does it hang indefinitely ? Or just for a while?
Also, can you provide the exact commit in which this problem start?
(just to be sure)

As a debugging aid, can you also define the Dprintks in the code? I've
seen hangs before in which the processor was indeed executing its init
sequence, (although it did not seem to), but was hanging in the
calibrate loop.

Thanks

2008-03-20 05:00:14

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

On Wed, Mar 19, 2008 at 9:40 PM, Glauber Costa <[email protected]> wrote:
>
> Yinghai Lu wrote:
> > On Wed, Mar 19, 2008 at 8:00 PM, Yinghai Lu <[email protected]> wrote:
> >> On Wed, Mar 19, 2008 at 7:18 PM, Yinghai Lu <[email protected]> wrote:
> >> > On Wed, Mar 19, 2008 at 10:35 AM, Ingo Molnar <[email protected]> wrote:
> >> > >
> >> > > * Glauber de Oliveira Costa <[email protected]> wrote:
> >> > >
> >> > > > Testing and bisectability:
> >> > > >
> >> > > > The end result was tested in all my hardware (which includes qemu ;-).
> >> > > > It does not mean it will boot _your_ hardware, but I did my best ;-)
> >> > > >
> >> > > > The tree at least compiles in more than 20 randconfigs (for each of
> >> > > > x86_64 and i386) For i386, each of the subarchitectures was compiled
> >> > > > at least once. (By compile, I obviously mean, every patch,
> >> > > > individually)
> >> > >
> >> > > very nice work! I'll pick it up - and i'm not too worried about
> >> > > breakages because at 80 patches granularity any problem should be
> >> > > identifiable in a very finegrained way.
> >> > >
> >> >
> >> > it broke 4 sockets quad core above with 64 bit
> >> >
> >> > Booting processor 11/15 ip 6000
> >> > Initializing CPU#11
> >> > masked ExtINT on CPU#11
> >> > Calibrating delay using timer specific routine.. 4589.46 BogoMIPS (lpj=9178934)
> >> > CPU: L1 I Cache: 64K (64 bytes/line), D cache 64K (64 bytes/line)
> >> > CPU: L2 Cache: 512K (64 bytes/line)
> >> > CPU 11/f -> Node 2
> >> > CPU: Physical Processor ID: 2
> >> > CPU: Processor Core ID: 3
> >> > CPU11: Quad-Core AMD Opteron(tm) Processor 8356 stepping 03
> >> > checking TSC synchronization [CPU#0 -> CPU#11]: passed.
> >> > Booting processor 12/16 ip 6000
> >> >
> >> > looks like local apic id up 4 bit is masked out. so can not start 0x10
> >> > above any more.
> >>
> >> in wakeup_secondary_via_INIT
> >> before the patchsets
> >> 64 bit code:
> >>
> >> /*
> >> * Send IPI
> >> */
> >> apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
> >> | APIC_DM_INIT);
> >>
> >>
> >> after patchset
> >>
> >> /* Boot on the stack */
> >> /* Kick the second */
> >> apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
> >>
> >> So that is wrong! esp for system has ext apic id that is has 8 bits
> >> instead of 4 bits.
> >>
> >
> > it seems there is two wakeup_secondary_cpu. one for NMI and one INIT.
> >
> > but should have
> >
> > #define WAKE_SECONDARY_VIA_INIT
> >
> > for x86_64
> >
> > but after
> >
> > #ifdef CONFIG_X86_64
> > #undef WAKE_SECONDARY_VIA_NMI
> > #define WAKE_SECONDARY_VIA_INIT
> > #endif
> >
> > it still doesn't work.
> >
> > YH
> Thanks for the testing Yinghai. I'll take a deeper look as soon as I
> can. The two routines are provided, since i386 numa-q inits the startup
> sequence through NMIs. The _VIA_INIT is already defined in x86_64 in the
> mach-default/ headers.
>
> What happens exactly? Does it hang indefinitely ? Or just for a while?
> Also, can you provide the exact commit in which this problem start?
> (just to be sure)

hang indefinitely.

maybe some apic code merge problem...

YH

2008-03-20 06:56:58

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 58/79] [PATCH] include mach_apic.h in smpboot_64.c and smpboot.c

On Wed, Mar 19, 2008 at 10:25 AM, Glauber de Oliveira Costa
<[email protected]> wrote:
> From: Glauber Costa <[email protected]>
>
> After the inclusion, a lot of files needs fixing for conflicts,
> some of them in the headers themselves, to accomodate for both
> i386 and x86_64 versions.
>
> Signed-off-by: Glauber Costa <[email protected]>
> ---
> arch/x86/kernel/acpi/boot.c | 2 ++
> arch/x86/kernel/mpparse_64.c | 2 ++
> arch/x86/kernel/smpboot.c | 2 ++
> arch/x86/kernel/smpboot_64.c | 1 +
> arch/x86/vdso/Makefile | 2 +-
> include/asm-x86/apic.h | 1 -
> include/asm-x86/apicdef.h | 6 ------
> include/asm-x86/mach-default/mach_apic.h | 11 +++++++++++
> include/asm-x86/mach-default/mach_apicdef.h | 5 +++++
> include/asm-x86/smp_64.h | 9 +--------
> 10 files changed, 25 insertions(+), 16 deletions(-)

please don't.

before this patch
include/asm-x86/mach_apic.h is only for x86_64 only
include/asm-x86/mach-default/mach_apic.h is for i386 only.

and both have __ASM_MACH_APIC_H defined.

may need another name?

YH

2008-03-20 10:39:20

by Maciej W. Rozycki

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

On Wed, 19 Mar 2008, Glauber de Oliveira Costa wrote:

> EOI is a write-only register. Using write around will have the effect
> of reading it, which will make all subsequent reads of the ESR register
> to return an error code. It was unnotices for quite a while because main sources
> of reading the ESR register where done prior to apic interrupt enabling.

Are you sure this actually triggers for APIC chips affected by the
erratum in question? And please note that for them the effect of two
consecutive writes will be much more disastrous than setting a bit in the
ESR register.

Maciej

2008-03-20 14:29:57

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 58/79] [PATCH] include mach_apic.h in smpboot_64.c and smpboot.c

Yinghai Lu wrote:
> On Wed, Mar 19, 2008 at 10:25 AM, Glauber de Oliveira Costa
> <[email protected]> wrote:
>> From: Glauber Costa <[email protected]>
>>
>> After the inclusion, a lot of files needs fixing for conflicts,
>> some of them in the headers themselves, to accomodate for both
>> i386 and x86_64 versions.
>>
>> Signed-off-by: Glauber Costa <[email protected]>
>> ---
>> arch/x86/kernel/acpi/boot.c | 2 ++
>> arch/x86/kernel/mpparse_64.c | 2 ++
>> arch/x86/kernel/smpboot.c | 2 ++
>> arch/x86/kernel/smpboot_64.c | 1 +
>> arch/x86/vdso/Makefile | 2 +-
>> include/asm-x86/apic.h | 1 -
>> include/asm-x86/apicdef.h | 6 ------
>> include/asm-x86/mach-default/mach_apic.h | 11 +++++++++++
>> include/asm-x86/mach-default/mach_apicdef.h | 5 +++++
>> include/asm-x86/smp_64.h | 9 +--------
>> 10 files changed, 25 insertions(+), 16 deletions(-)
>
> please don't.
>
> before this patch
> include/asm-x86/mach_apic.h is only for x86_64 only
> include/asm-x86/mach-default/mach_apic.h is for i386 only.
>
> and both have __ASM_MACH_APIC_H defined.
>
> may need another name?
>
> YH
Another name is possible, but I'd prefer to get rid of the
asm-x86/mach_apic.h. The goal here is to have things integrated, so
unless really necessary, this is prefered.

Is this related to your problem anyhow? (just in curiosity)

2008-03-20 15:09:19

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

Maciej W. Rozycki wrote:
> On Wed, 19 Mar 2008, Glauber de Oliveira Costa wrote:
>
>> EOI is a write-only register. Using write around will have the effect
>> of reading it, which will make all subsequent reads of the ESR register
>> to return an error code. It was unnotices for quite a while because main sources
>> of reading the ESR register where done prior to apic interrupt enabling.
>
> Are you sure this actually triggers for APIC chips affected by the
> erratum in question? And please note that for them the effect of two
> consecutive writes will be much more disastrous than setting a bit in the
> ESR register.
>
> Maciej

I'm not _sure_, but I can't find anything in the errata list that states
otherwise. It would be great that anyone has such a system to test it.
But with the current conditions, it will break bootup code. In case it
is really a problem, we'd need to make a special case for that.

2008-03-20 18:00:29

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 58/79] [PATCH] include mach_apic.h in smpboot_64.c and smpboot.c

On Thu, Mar 20, 2008 at 7:25 AM, Glauber Costa <[email protected]> wrote:
>
> Yinghai Lu wrote:
> >> 10 files changed, 25 insertions(+), 16 deletions(-)
> >
> > please don't.
> >
> > before this patch
> > include/asm-x86/mach_apic.h is only for x86_64 only
> > include/asm-x86/mach-default/mach_apic.h is for i386 only.
> >
> > and both have __ASM_MACH_APIC_H defined.
> >
> > may need another name?
> >
> > YH
> Another name is possible, but I'd prefer to get rid of the
> asm-x86/mach_apic.h. The goal here is to have things integrated, so
> unless really necessary, this is prefered.
>
> Is this related to your problem anyhow? (just in curiosity)

No

YH

2008-03-20 22:27:59

by Maciej W. Rozycki

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

On Thu, 20 Mar 2008, Glauber Costa wrote:

> > Are you sure this actually triggers for APIC chips affected by the erratum
> > in question? And please note that for them the effect of two consecutive
> > writes will be much more disastrous than setting a bit in the ESR register.
>
> I'm not _sure_, but I can't find anything in the errata list that states
> otherwise. It would be great that anyone has such a system to test it. But
> with the current conditions, it will break bootup code. In case it is really a
> problem, we'd need to make a special case for that.

I have dug out the relevant erratum -- it is the 11AP one as referred to
from arch/x86/kernel/smp_32.c and the text even mentions the EOI register
explicitly:

"This problem affects systems that use HOLD/HLDA or BOFF# and enable the
local APIC of the CPU. If the second APIC write cycle is an EOI (End of
Interrupt) cycle, the CPU will stop servicing subsequent interrupts of
equal or less priority. This may cause the system to hang. If the second
APIC write cycle is not an EOI, the failure mode would depend on the
particular APIC register that is not updated correctly."

But on this occasion I took the opportunity to refresh my memory on the
ESR register and there is apparently no bit there, at least up to
Pentium4, that would signify an error resulting from an incorrect access
type -- only accesses to invalid register indices are marked as errors.

Which bit of the ESR can you see set as a result of using an RMW cycle to
the EOI register and with what kind of CPU/APIC? And why wouldn't it have
affected older kernels? -- the error interrupt has been kept enabled by
Linux for ages and writes to the EOI register are frequent enough it would
be hard to miss the resulting flood of errors. Hmm...

Maciej

2008-03-21 22:14:21

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

On Fri, Mar 21, 2008 at 2:41 PM, Yinghai Lu <[email protected]> wrote:
>
> On Fri, Mar 21, 2008 at 1:03 PM, Yinghai Lu <[email protected]> wrote:
> >
> > On Fri, Mar 21, 2008 at 12:55 PM, Ingo Molnar <[email protected]> wrote:
> > >
> > > * Yinghai Lu <[email protected]> wrote:
> > >
> > >
> > > > how to bisect x86.git tree?. it always said it can not bisect seeked
> > > > tree.
> > >
> > > ah. Does this work:
> > >
> > > git-checkout my-tree x86/latest
> > >
> > > git-bisect start
> > > git-bisect good x86/base
> > > git-bisect bad x86/latest
> > >
> > > x86/base is the Linus tree that x86.git is based against. You can see
> > > all the x86.git/latest changes by doing:
> > >
> > > git-log x86/base..x86/latest
> > >
> > > Ingo
> > >
> >
> > works. will let you know the result.
> >
>
> yhlu@mpk:~/xx/xx/kernel/x86/linux-2.6> git-bisect bad
> d1c707188ad646c8094cac9afb1738e7d0196ff2 is first bad commit
> commit d1c707188ad646c8094cac9afb1738e7d0196ff2
> Author: Glauber de Oliveira Costa <[email protected]>
> Date: Wed Mar 19 14:25:53 2008 -0300
>
> x86: include mach_apic.h in smpboot_64.c and smpboot.c
>
> After the inclusion, a lot of files needs fixing for conflicts,
> some of them in the headers themselves, to accomodate for both
> i386 and x86_64 versions.
>
> [ [email protected]: build fix ]
>
> Signed-off-by: Glauber Costa <[email protected]>
> Signed-off-by: Ingo Molnar <[email protected]>
>
> :040000 040000 19f574e64bb8003bbe984f3a8c1315db969dfdcd
> 6ffe96588c77bc936705599fa110107856201115 M arch
> :040000 040000 61269347ad4f384ed85cc87c4f2d004ed94492ac
> 8f5c713da25579a3cdf63db3d4c2f795261d0521 M include
> yhlu@mpk:~/xx/xx/kernel/x86/linux-2.6>
>

attached patch fix that.

YH


Attachments:
(No filename) (1.79 kB)
smpboo_intergration_fix.patch (755.00 B)
Download all attachments

2008-03-21 22:19:14

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration


* Yinghai Lu <[email protected]> wrote:

> attached patch fix that.

thanks Yinghai, applied.

Ingo

2008-03-21 22:37:39

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 58/79] [PATCH] include mach_apic.h in smpboot_64.c and smpboot.c

On Thu, Mar 20, 2008 at 7:25 AM, Glauber Costa <[email protected]> wrote:
>
> Yinghai Lu wrote:
> > On Wed, Mar 19, 2008 at 10:25 AM, Glauber de Oliveira Costa
> > <[email protected]> wrote:
> >> From: Glauber Costa <[email protected]>
> >>
> >> After the inclusion, a lot of files needs fixing for conflicts,
> >> some of them in the headers themselves, to accomodate for both
> >> i386 and x86_64 versions.
> >>
> >> Signed-off-by: Glauber Costa <[email protected]>
> >> ---
> >> arch/x86/kernel/acpi/boot.c | 2 ++
> >> arch/x86/kernel/mpparse_64.c | 2 ++
> >> arch/x86/kernel/smpboot.c | 2 ++
> >> arch/x86/kernel/smpboot_64.c | 1 +
> >> arch/x86/vdso/Makefile | 2 +-
> >> include/asm-x86/apic.h | 1 -
> >> include/asm-x86/apicdef.h | 6 ------
> >> include/asm-x86/mach-default/mach_apic.h | 11 +++++++++++
> >> include/asm-x86/mach-default/mach_apicdef.h | 5 +++++
> >> include/asm-x86/smp_64.h | 9 +--------
> >> 10 files changed, 25 insertions(+), 16 deletions(-)
> >
> > please don't.
> >
> > before this patch
> > include/asm-x86/mach_apic.h is only for x86_64 only
> > include/asm-x86/mach-default/mach_apic.h is for i386 only.
> >
> > and both have __ASM_MACH_APIC_H defined.
> >
> > may need another name?
> >
> > YH
> Another name is possible, but I'd prefer to get rid of the
> asm-x86/mach_apic.h. The goal here is to have things integrated, so
> unless really necessary, this is prefered.

anyway, before that I hope you can rename include/asm-x86/mach_apic.h
to include/asm-x86/apic_ext.h

you may move bits from apic_ext.h to mach-default/mach_apic.h later.

YH

2008-03-24 14:52:42

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

Maciej W. Rozycki wrote:
> On Thu, 20 Mar 2008, Glauber Costa wrote:
>
>>> Are you sure this actually triggers for APIC chips affected by the erratum
>>> in question? And please note that for them the effect of two consecutive
>>> writes will be much more disastrous than setting a bit in the ESR register.
>> I'm not _sure_, but I can't find anything in the errata list that states
>> otherwise. It would be great that anyone has such a system to test it. But
>> with the current conditions, it will break bootup code. In case it is really a
>> problem, we'd need to make a special case for that.
>
> I have dug out the relevant erratum -- it is the 11AP one as referred to
> from arch/x86/kernel/smp_32.c and the text even mentions the EOI register
> explicitly:
>
> "This problem affects systems that use HOLD/HLDA or BOFF# and enable the
> local APIC of the CPU. If the second APIC write cycle is an EOI (End of
> Interrupt) cycle, the CPU will stop servicing subsequent interrupts of
> equal or less priority. This may cause the system to hang. If the second
> APIC write cycle is not an EOI, the failure mode would depend on the
> particular APIC register that is not updated correctly."
>
> But on this occasion I took the opportunity to refresh my memory on the
> ESR register and there is apparently no bit there, at least up to
> Pentium4, that would signify an error resulting from an incorrect access
> type -- only accesses to invalid register indices are marked as errors.
>
> Which bit of the ESR can you see set as a result of using an RMW cycle to
> the EOI register and with what kind of CPU/APIC? And why wouldn't it have
> affected older kernels? -- the error interrupt has been kept enabled by
> Linux for ages and writes to the EOI register are frequent enough it would
> be hard to miss the resulting flood of errors. Hmm...
>
I see bit 7 - Illegal Register Address being set.
I believe the reason we never saw it, is that the ESR register is not
checked that often when interrupts are enabled. In the new bootup state
machine, that is inherited from x86_64, we call do_boot_cpu with irqs
clearly enabled, and check esr in the process.

But I can understand from the spec you posted that this is clearly an
error. So I'd have better come up with a new solution from this

2008-03-24 15:13:36

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 0/79] smpboot integration

Ingo Molnar wrote:
> * Yinghai Lu <[email protected]> wrote:
>
>> attached patch fix that.
>
> thanks Yinghai, applied.
Thanks for seeking and patching this, Yinghai. The granularity proved
quite useful once more ;-)

2008-03-24 23:19:30

by Maciej W. Rozycki

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

On Mon, 24 Mar 2008, Glauber Costa wrote:

> I see bit 7 - Illegal Register Address being set.

Hmm, it looks like the only one to be reasonably set under these
conditions, but I have never seen it reported for a read cycle to the EOI
register anyway, so I suppose it has to be a relatively recent addition.

> I believe the reason we never saw it, is that the ESR register is not checked
> that often when interrupts are enabled. In the new bootup state machine, that

Well, as I wrote, the error interrupt handler is always enabled,
reporting the state recorded in the ESR register as soon as an error
condition triggers and if an RMW cycle was a problem before, we would have
seen a flood of reports from people -- like we indeed have many times for
inter-APIC bus data corruption that triggers the same event (using bits
3:0 in the ESR as relevant).

> is inherited from x86_64, we call do_boot_cpu with irqs clearly enabled, and
> check esr in the process.

Please note that ESR may hold some leftover state from whatever happened
before Linux has taken control, so it is reasonable and I think actually
recommended by Intel (FWIW) to clear the register before enabling the
error interrupt. For how to clear the ESR properly, please see
setup_local_APIC() -- subtle differences and errata in various APIC
implementations have made it more complicated than necessary, sigh...

> But I can understand from the spec you posted that this is clearly an error.
> So I'd have better come up with a new solution from this

Well, with CONFIG_X86_GOOD_APIC set there is no RMW access to the ESR as
apic_write_around() expands to apic_write(). And the option is meant to
be clear only for the original integrated APIC as included in the Pentium
processor ("Pentium-Classic" in the Kconfig nomenclature). I have no
means to test such a system, but I still have a working dual-Pentium-MMX
machine, which features local APICs that should be the same modulo errata.
I may check and see whether a RMW cycle to the ESR triggers any problems
with this computer, but the box is currently at the other end of the
continent, so it will take a while.

I have asked this question already: what kind of CPU are you running on?
Do you really need to have CONFIG_X86_GOOD_APIC clear with it?

Maciej

2008-03-25 12:40:52

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

"Maciej W. Rozycki" <[email protected]> writes:
>
> Please note that ESR may hold some leftover state from whatever happened
> before Linux has taken control, so it is reasonable and I think actually
> recommended by Intel (FWIW) to clear the register before enabling the
> error interrupt. For how to clear the ESR properly, please see
> setup_local_APIC() -- subtle differences and errata in various APIC
> implementations have made it more complicated than necessary, sigh...

iirc a lot of the ESR weirdness was on NUMAQ only, which is down to one
of two last machines running Linux which will hopefully die soon ...

-Andi

2008-03-25 13:43:51

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

Maciej W. Rozycki wrote:
>> is inherited from x86_64, we call do_boot_cpu with irqs clearly enabled, and
>> check esr in the process.
>
> Please note that ESR may hold some leftover state from whatever happened
> before Linux has taken control, so it is reasonable and I think actually
> recommended by Intel (FWIW) to clear the register before enabling the
> error interrupt. For how to clear the ESR properly, please see
> setup_local_APIC() -- subtle differences and errata in various APIC
> implementations have made it more complicated than necessary, sigh...
which excerpt specifically are you talking about ?
the only ESR mention I see in setup_local_APIC() is this:

/* Pound the ESR really hard over the head with a big hammer -
mbligh */
if (esr_disable) {
apic_write(APIC_ESR, 0);
apic_write(APIC_ESR, 0);
apic_write(APIC_ESR, 0);
apic_write(APIC_ESR, 0);
}
which seems more like a disablement.

the bootup code does clean it, tough, by writing and reading the ESR.

>> But I can understand from the spec you posted that this is clearly an error.
>> So I'd have better come up with a new solution from this
>
> Well, with CONFIG_X86_GOOD_APIC set there is no RMW access to the ESR as
> apic_write_around() expands to apic_write(). And the option is meant to
> be clear only for the original integrated APIC as included in the Pentium
> processor ("Pentium-Classic" in the Kconfig nomenclature). I have no
> means to test such a system, but I still have a working dual-Pentium-MMX
> machine, which features local APICs that should be the same modulo errata.
> I may check and see whether a RMW cycle to the ESR triggers any problems
> with this computer, but the box is currently at the other end of the
> continent, so it will take a while.
>
> I have asked this question already: what kind of CPU are you running on?
> Do you really need to have CONFIG_X86_GOOD_APIC clear with it?
>
My testings that triggered that were with qemu, with randconfigs.
Probably it has a good apic, but it is good that it triggered anyway.
Otherwise I'd never see it.

2008-03-25 15:48:58

by Maciej W. Rozycki

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

On Tue, 25 Mar 2008, Glauber Costa wrote:

> the only ESR mention I see in setup_local_APIC() is this:
>
> /* Pound the ESR really hard over the head with a big hammer - mbligh
> */
> if (esr_disable) {
> apic_write(APIC_ESR, 0);
> apic_write(APIC_ESR, 0);
> apic_write(APIC_ESR, 0);
> apic_write(APIC_ESR, 0);
> }
> which seems more like a disablement.

There is more later on...

> the bootup code does clean it, tough, by writing and reading the ESR.

... basically for the original Pentium and Pentium/MMX APIC you only had
to read the ESR to get at the bits. The read would clear them as well as
a side-effect. Although at that stage already it was mentioned in the
spec that for future compatibility a write of zero beforehand (ignored as
the register was r/o) should be performed. Which indeed became a
requirement from PentiumPro onwards as with these processors it was the
write that copied the internal error latches into the visible ESR
register. Except that some Pentium APICs had an erratum, where ESR was
indeed r/w and the leading write of zero would actually clear the register
losing the recorded state, so it had to be avoided despite the
recommendation. Hence the code you can see within:

if (integrated && !esr_disable) {
}

I suppose other APIC implementers were not that keen on keeping bug
compatibility, so chances are other APIC core work just fine as specified
by the architecture (for whatever the meaning of "fine" is).

Note the usual APIC error interrupt handler is smp_error_interrupt().

> > I have asked this question already: what kind of CPU are you running on?
> > Do you really need to have CONFIG_X86_GOOD_APIC clear with it?
> >
> My testings that triggered that were with qemu, with randconfigs. Probably it
> has a good apic, but it is good that it triggered anyway. Otherwise I'd never
> see it.

Ah, I see -- it may be worth checking what actual hardware does and
fixing QEMU if necessary for it to match reality then. ;-)

OTOH, if actual modern hardware triggered such an error, then for the
sake of a generic "runs everywhere" kernel either ack_APIC_irq() or even
apic_write_around() could be modified to perform a run-time check if
configured with !CONFIG_X86_GOOD_APIC and avoid the read if unnecessary;
it's an erratum workaround after all and SMP Pentium systems suffering
from this bug (UP Pentium systems did not nor had a way to enable the
local APIC normally) are probably an insignificant minority if any at all
left these days. Therefore it should be a negligible sacrifice of
performance.

Maciej

2008-03-25 22:42:28

by Glauber Costa

[permalink] [raw]
Subject: Re: [PATCH 45/79] [PATCH] fix apic acking of irqs

Maciej W. Rozycki wrote:
> On Tue, 25 Mar 2008, Glauber Costa wrote:
>
>> the only ESR mention I see in setup_local_APIC() is this:
>>
>> /* Pound the ESR really hard over the head with a big hammer - mbligh
>> */
>> if (esr_disable) {
>> apic_write(APIC_ESR, 0);
>> apic_write(APIC_ESR, 0);
>> apic_write(APIC_ESR, 0);
>> apic_write(APIC_ESR, 0);
>> }
>> which seems more like a disablement.
>
> There is more later on...
>
>> the bootup code does clean it, tough, by writing and reading the ESR.
>
> ... basically for the original Pentium and Pentium/MMX APIC you only had
> to read the ESR to get at the bits. The read would clear them as well as
> a side-effect. Although at that stage already it was mentioned in the
> spec that for future compatibility a write of zero beforehand (ignored as
> the register was r/o) should be performed. Which indeed became a
> requirement from PentiumPro onwards as with these processors it was the
> write that copied the internal error latches into the visible ESR
> register. Except that some Pentium APICs had an erratum, where ESR was
> indeed r/w and the leading write of zero would actually clear the register
> losing the recorded state, so it had to be avoided despite the
> recommendation. Hence the code you can see within:
>
> if (integrated && !esr_disable) {
> }
>
> I suppose other APIC implementers were not that keen on keeping bug
> compatibility, so chances are other APIC core work just fine as specified
> by the architecture (for whatever the meaning of "fine" is).
>
> Note the usual APIC error interrupt handler is smp_error_interrupt().
>
>>> I have asked this question already: what kind of CPU are you running on?
>>> Do you really need to have CONFIG_X86_GOOD_APIC clear with it?
>>>
>> My testings that triggered that were with qemu, with randconfigs. Probably it
>> has a good apic, but it is good that it triggered anyway. Otherwise I'd never
>> see it.
>
> Ah, I see -- it may be worth checking what actual hardware does and
> fixing QEMU if necessary for it to match reality then. ;-)
>
> OTOH, if actual modern hardware triggered such an error, then for the
> sake of a generic "runs everywhere" kernel either ack_APIC_irq() or even
> apic_write_around() could be modified to perform a run-time check if
> configured with !CONFIG_X86_GOOD_APIC and avoid the read if unnecessary;
> it's an erratum workaround after all and SMP Pentium systems suffering
> from this bug (UP Pentium systems did not nor had a way to enable the
> local APIC normally) are probably an insignificant minority if any at all
> left these days. Therefore it should be a negligible sacrifice of
> performance.
I just tested in some real i386 that I have around here, and the reading
of EOI does not seem to be illegal. (Well, at least in those I've tested).

OTOH, ignoring the read in qemu makes the tree boot just okay. So I
agree with you now, we might well fix qemu, and revert this patch.

Ingo, any word on that?



> Maciej