linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
@ 2017-05-10 13:44 Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 01/12] x86/apic: Replace init_bsp_APIC() with apic_virtual_wire_mode_setup() Dou Liyang
                   ` (12 more replies)
  0 siblings, 13 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

According to Ingo's and Eric's advice[1,2], Try my best to optimize the 
init of interrupt delivery mode for x86.

MP specification defines three different interrupt modes as follows:

 1. PIC Mode
 2. Virtual Wire Mode
 3. Symmetric I/O Mode

Currently, in kernel,

1. Setup Virtual Wire Mode during IRQ initialization( step 1
in the following figure).

2. Enable and Setup Symmetric I/O Mode either during the
SMP-capable system prepares CPUs(step 2) or during the UP system 
initializes itself(step 3).

  start_kernel
+---------------+
|
+--> .......
|
|    setup_arch
+--> +-------+
|
|    init_IRQ
+-> +--+-----+
|      |        init_ISA_irqs
|      +------> +-+--------+
|                 |         +----------------+
+--->             +------>  | 1.init_bsp_APIC|
|     .......               +----------------+
+--->
|     rest_init
+--->---+-----+
|       |   kernel_init
|       +> ----+-----+
|              |   kernel_init_freeable
|              +->  ----+-------------+
|                       |     smp_prepare_cpus
|                       +---> +----+---------+
|                       |          |   +-------------------+
|                       |          +-> |2.  apic_bsp_setup |
|                       |              +-------------------+
|                       |
v                       |     smp_init
                        +---> +---+----+
                                  |    +-------------------+
                                  +--> |3.  apic_bsp_setup |
                                       +-------------------+

The purpose of this patches is unifying these setup steps and executing
as soon as possible as follows:

   start_kernel
---------------+
|
|
|
|    x86_late_time_init
+---->---+------------+
|        |
|        |      +------------------------+
|        +----> | 4. init_interrupt_mode |
|               +------------------------+
v

And construct a selector to wrap all the switches and make them
maintain and read easily.

Original:

+-----------------------------------------------------+
| smp_found_config || !boot_cpu_has(X86_FEATURE_APIC) |
+-----------------------------------------------------+
      |true, PIC MODE   |false, VIRTUAL WIRE MODE
      |                 |
   +--v-----------------v-----------+
   |!smp_found_config && !acpi_lapic+-----+
   +--------------------------------+     |
    |false                                |
    |                                     |
 +--v----------------------------+        |
 |!boot_cpu_has(X86_FEATURE_APIC)+   true |
 +------------------+------------+        |
    |false          |                     |
    v               |              +------v-----+ true
SYMMETRIC IO MODE   |              |disable_apic+------> PIC MODE
                    |              +------------+
                    |true              |false
                    |              +---v---------------------------+
             +------v------+       |!boot_cpu_has(X86_FEATURE_APIC)|
             |!disable_apic|       +---------------------------+---+
             +------+------+           |false                  |true
                    |             +----v------------+          v
                    v             |!smp_found_config+----+  PIC MODE
               PIC MODE           +-----------------+    |
                                       |false            |true
                                       v                 v
                               SYMMETRIC IO MODE  VIRTUAL WIRE MODE
Now:

       +------------+
       |disable_apic+--------------------+
       +------------+       true         |
              |false                     |
              |                          |
 +------------v------------------+       |
 |!boot_cpu_has(X86_FEATURE_APIC)+-------+
 +-------------------------------+  true |
              |false                     |
              |                          |
      +-------v---------+                v
      |!smp_found_config|            PIC MODE
      +---------------+-+
       |false         |true
       |              |
       v          +---v---------+
SYMMETRIC IO MODE | !acpi_lapic |
                  +------+------+
                         |
                         v
                   VIRTUAL WIRE MODE 

By the way, Also fix a bug about kexec[3].

[1]. https://lkml.org/lkml/2016/8/2/929
[2]. https://lkml.org/lkml/2016/8/1/506
[3]. https://lkml.org/lkml/2016/7/25/1118

Changes V2 --> V3:

  - Rebase the patches.
  - Change two function name:
      apic_bsp_mode_check --> apic_interrupt_mode_select
      init_interrupt_mode --> apic_interrupt_mode_init
  - Find a new waiting way to check whether timer IRQs work or not
  - Refine the switch logic in apic_interrupt_mode_init()
  - Consistently start sentences with upper case letters
  - Fix some typos and comments
  - Try my best to rewrite some changelog again

Changes since V1:

  - Move the initialization from init_IRQ() to x86_late_time_init()
  - Use a threshold to refactor the check logic in timer_irq_works()
  - Rename the framework to a selector
  - Split two patches
  - Consistently start sentences with upper case letters
  - Fix some typos
  - Rewrite the changelog

Dou Liyang (12):
  x86/apic: Replace init_bsp_APIC() with apic_virtual_wire_mode_setup()
  x86/apic: Construct a selector for the interrupt delivery mode
  x86/apic: Prepare for unifying the interrupt delivery modes setup
  x86/time: Initialize interrupt mode behind timer init
  x86/ioapic: Refactor the delay logic in timer_irq_works()
  x86/apic: Split local APIC timer setup from the APIC setup
  x86/apic: Move the logical APIC ID setup from apic_bsp_setup()
  x86/apic: Make interrupt mode setup earlier for SMP-capable system
  x86/apic: Setup interrupt mode earlier in case of no SMP motherboard
  x86/apic: Make the interrupt mode setup earlier for UP system
  x86/apic: Mark the apic_interrupt_mode extern for disable_smp()
  x86/apic: Remove the apic_virtual_wire_mode_setup()

 arch/x86/include/asm/apic.h    |  15 +++-
 arch/x86/kernel/apic/apic.c    | 185 +++++++++++++++++++++--------------------
 arch/x86/kernel/apic/io_apic.c |  46 +++++++++-
 arch/x86/kernel/irqinit.c      |   3 -
 arch/x86/kernel/smpboot.c      |  65 ++++-----------
 arch/x86/kernel/time.c         |   8 ++
 6 files changed, 174 insertions(+), 148 deletions(-)

-- 
2.5.5

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 01/12] x86/apic: Replace init_bsp_APIC() with apic_virtual_wire_mode_setup()
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 02/12] x86/apic: Construct a selector for the interrupt delivery mode Dou Liyang
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

The init_bsp_APIC() sets up virtual wire mode through the local APIC.

The function name implies that the BSP's APIC will be initialized here,
which is unsuitable, while its initialization actually locates almost
at the end of start_kernel(). And the CONFIG X86_64 is also imply the
X86_LOCAL_APIC is y.

Rename it with a straightforward name, remove the redundant macros to
increase readability by adding an empty stub for X86_LOCAL_APIC = n.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/include/asm/apic.h | 3 ++-
 arch/x86/kernel/apic/apic.c | 4 ++--
 arch/x86/kernel/irqinit.c   | 5 ++---
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index bdffcd9..4f4519b 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -127,7 +127,7 @@ extern void disconnect_bsp_APIC(int virt_wire_setup);
 extern void disable_local_APIC(void);
 extern void lapic_shutdown(void);
 extern void sync_Arb_IDs(void);
-extern void init_bsp_APIC(void);
+extern void apic_virtual_wire_mode_setup(void);
 extern void setup_local_APIC(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
@@ -170,6 +170,7 @@ static inline void disable_local_APIC(void) { }
 # define setup_boot_APIC_clock x86_init_noop
 # define setup_secondary_APIC_clock x86_init_noop
 static inline void lapic_update_tsc_freq(void) { }
+static inline void apic_virtual_wire_mode_setup(void) {}
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_X2APIC
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 2d75faf..6bf7249 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1158,9 +1158,9 @@ void __init sync_Arb_IDs(void)
 }
 
 /*
- * An initial setup of the virtual wire mode.
+ * Setup the through-local-APIC virtual wire mode.
  */
-void __init init_bsp_APIC(void)
+void __init apic_virtual_wire_mode_setup(void)
 {
 	unsigned int value;
 
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 7468c69..e4f89b6 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -72,9 +72,8 @@ void __init init_ISA_irqs(void)
 	struct irq_chip *chip = legacy_pic->chip;
 	int i;
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
-	init_bsp_APIC();
-#endif
+	apic_virtual_wire_mode_setup();
+
 	legacy_pic->init(0);
 
 	for (i = 0; i < nr_legacy_irqs(); i++)
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 02/12] x86/apic: Construct a selector for the interrupt delivery mode
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 01/12] x86/apic: Replace init_bsp_APIC() with apic_virtual_wire_mode_setup() Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 03/12] x86/apic: Prepare for unifying the interrupt delivery modes setup Dou Liyang
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Now, there are many switches in kernel which are used to determine
the final interrupt delivery mode, as shown below:

1) kconfig:
   CONFIG_X86_64; CONFIG_X86_LOCAL_APIC; CONFIG_x86_IO_APIC
2) kernel option: disable_apic; skip_ioapic_setup
3) CPU Capability: boot_cpu_has(X86_FEATURE_APIC)
4) MP table: smp_found_config
5) ACPI: acpi_lapic; acpi_ioapic; nr_ioapic

These switches are disordered and scattered and there are also some
dependencies between each other. These make the code difficult to
maintain and read.

Construct a selector to unify them into a single function, then,
Use this selector to get an interrupt delivery mode directly.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
The selector logic:
       +------------+
       |disable_apic+--------------------+
       +------------+       true         |
              |false                     |
              |                          |
 +------------v------------------+       |
 |!boot_cpu_has(X86_FEATURE_APIC)+-------+
 +-------------------------------+  true |
              |false                     |
              |                          |
      +-------v---------+                v
      |!smp_found_config|            PIC MODE
      +---------------+-+
       |false         |true
       |              |
       v          +---v---------+
SYMMETRIC IO MODE | !acpi_lapic |
                  +------+------+
                         |
                         v
                   VIRTUAL WIRE MODE 
v2 --> v3:
  modify some comments.
 arch/x86/kernel/apic/apic.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 6bf7249..3342f144 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1157,6 +1157,67 @@ void __init sync_Arb_IDs(void)
 			APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
+enum apic_interrupt_mode {
+	APIC_PIC = 0,
+	APIC_VIRTUAL_WIRE,
+	APIC_SYMMETRIC_IO,
+	APIC_MODE_COUNT
+};
+
+static int __init apic_interrupt_mode_select(void)
+{
+	/* Check kernel option */
+	if (disable_apic) {
+		pr_info("APIC disabled via kernel command line\n");
+		return APIC_PIC;
+	}
+
+	/* Check BIOS */
+#ifdef CONFIG_X86_64
+	/* On 64-bit, the APIC must be integrated */
+	if (!boot_cpu_has(X86_FEATURE_APIC)) {
+		disable_apic = 1;
+		pr_info("APIC disabled by BIOS\n");
+		return APIC_PIC;
+	}
+#else
+	/*
+	 * On 32-bit, check whether there is a separate chip or integrated
+	 * APIC
+	 */
+
+	/* Has a local APIC ? */
+	if (!boot_cpu_has(X86_FEATURE_APIC) &&
+		APIC_INTEGRATED(boot_cpu_apic_version)) {
+		disable_apic = 1;
+		pr_err(FW_BUG "Local APIC %d not detected, force emulation\n",
+				       boot_cpu_physical_apicid);
+		return APIC_PIC;
+	}
+
+	/* Has a separate chip ? */
+	if (!boot_cpu_has(X86_FEATURE_APIC) && !smp_found_config) {
+		disable_apic = 1;
+
+		return APIC_PIC;
+	}
+#endif
+
+	/* Check MP table or ACPI MADT configuration */
+	if (!smp_found_config) {
+		disable_ioapic_support();
+
+		if (!acpi_lapic)
+			pr_info("ACPI MADT or MP table not detected\n");
+
+		return APIC_VIRTUAL_WIRE;
+	}
+
+	/* Other checks of APIC options will be done in each setup function */
+
+	return APIC_SYMMETRIC_IO;
+}
+
 /*
  * Setup the through-local-APIC virtual wire mode.
  */
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 03/12] x86/apic: Prepare for unifying the interrupt delivery modes setup
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 01/12] x86/apic: Replace init_bsp_APIC() with apic_virtual_wire_mode_setup() Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 02/12] x86/apic: Construct a selector for the interrupt delivery mode Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 04/12] x86/time: Initialize interrupt mode behind timer init Dou Liyang
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

There are three positions for initializing the interrupt delivery
modes:

1) In IRQ initial function, may setup the through-local-APIC
   virtual wire mode.

2) In an SMP-capable system, will try to switch to symmetric I/O
   model when preparing the cpus in native_smp_prepare_cpus().

3) In UP system with UP_LATE_INIT=y, will set up local APIC and
   I/O APIC in smp_init().

Switching to symmetric I/O mode is so late, which causes kernel
is in a mismatched mode at the beginning of booting time. And it
causes the dump-capture kernel hangs with 'notsc' option inherited
from 1st kernel option.

Preparatory patch to initialize an interrupt mode directly and provide
a new function apic_interrupt_mode_init() to unify that three positions
and do that setup as soon as possible.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
v2 --> v3:
  change the function name from init_interrupt_mode to 
  apic_interrupt_mode_init.

 arch/x86/include/asm/apic.h |  2 ++
 arch/x86/kernel/apic/apic.c | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 4f4519b..e9502e6 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -128,6 +128,7 @@ extern void disable_local_APIC(void);
 extern void lapic_shutdown(void);
 extern void sync_Arb_IDs(void);
 extern void apic_virtual_wire_mode_setup(void);
+extern void apic_interrupt_mode_init(void);
 extern void setup_local_APIC(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
@@ -171,6 +172,7 @@ static inline void disable_local_APIC(void) { }
 # define setup_secondary_APIC_clock x86_init_noop
 static inline void lapic_update_tsc_freq(void) { }
 static inline void apic_virtual_wire_mode_setup(void) {}
+static inline void apic_interrupt_mode_init(void) {}
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_X2APIC
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 3342f144..56be7f3 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1267,6 +1267,22 @@ void __init apic_virtual_wire_mode_setup(void)
 	apic_write(APIC_LVT1, value);
 }
 
+/* Init the interrupt delivery mode for the BSP */
+void __init apic_interrupt_mode_init(void)
+{
+	switch (apic_interrupt_mode_select()) {
+	case APIC_PIC:
+		pr_info("Keep in PIC mode(8259)\n");
+		return;
+	case APIC_VIRTUAL_WIRE:
+		pr_info("Switch to virtual wire mode\n");
+		return;
+	case APIC_SYMMETRIC_IO:
+		pr_info("Switch to symmectic I/O mode\n");
+		return;
+	}
+}
+
 static void lapic_setup_esr(void)
 {
 	unsigned int oldvalue, value, maxlvt;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 04/12] x86/time: Initialize interrupt mode behind timer init
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (2 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 03/12] x86/apic: Prepare for unifying the interrupt delivery modes setup Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-06-06  6:00   ` [RFC PATCH v4 " Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works() Dou Liyang
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

In start_kernel(), firstly, it works on the default interrupy mode, then
switch to the final mode. Normally, Booting with BIOS reset is OK.

But, At dump-capture kernel, it boot up without BIOS reset, default mode
may not be compatible with the actual registers, that causes the delivery
interrupt to fail.

Try to set up the final mode as soon as possible. according to the parts
which split from that initialization:

1) Set up the APIC/IOAPIC (including testing whether the timer
   interrupt works)

2) Calibrate TSC

3) Set up the local APIC timer

-- From Thomas Gleixner

Initializing the mode should be earlier than calibrating TSC as soon as
possible and needs testing whether the timer interrupt works at the same
time.

Add apic_interrupt_mode_init() just behind timers init, which meet the
above conditions.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/kernel/time.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index d39c091..23b074e 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -21,6 +21,7 @@
 #include <asm/timer.h>
 #include <asm/hpet.h>
 #include <asm/time.h>
+#include <asm/apic.h>
 
 #ifdef CONFIG_X86_64
 __visible volatile unsigned long jiffies __cacheline_aligned = INITIAL_JIFFIES;
@@ -84,6 +85,13 @@ void __init hpet_time_init(void)
 static __init void x86_late_time_init(void)
 {
 	x86_init.timers.timer_init();
+
+	/*
+	 * After PIT/HPET timers init, select and setup
+	 * the final interrupt mode for delivering IRQs.
+	 */
+	apic_interrupt_mode_init();
+
 	tsc_init();
 }
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works()
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (3 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 04/12] x86/time: Initialize interrupt mode behind timer init Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-26  8:10   ` [RFC PATCH v4 " Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 06/12] x86/apic: Split local APIC timer setup from the APIC setup Dou Liyang
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Kernel use timer_irq_works() to detects the timer IRQs. It calls
mdelay(10) to delay ten ticks and checks whether the timer IRQs work
or not. The mdelay() depends on the loops_per_jiffy which is set up
in calibrate_delay(). And in "notsc" case, calibrating delay also
should make sure the timer IRQs work well.

Now, initializing interrupt mode behind timer init makes the
timer_irq_works() in advance of calibrate_delay(). the mdelay()
doesn't work well in timer_irq_works().

Refactor the delay logic by waiting for some cycles. At the system
With X86_FEATURE_TSC, Use rdtsc(), others will call __delay() directly.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
v2 --> v3:
  Find a new way to for waiting.
  Reference to the realization of hpet_clocksource_register() by Thomas.

 arch/x86/kernel/apic/io_apic.c | 46 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 347bb9f..a63c19e 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1607,6 +1607,44 @@ static int __init notimercheck(char *s)
 }
 __setup("no_timer_check", notimercheck);
 
+static void delay_with_tsc(void)
+{
+	unsigned long long start, now;
+	unsigned long ticks = jiffies;
+
+	start = rdtsc();
+
+	/*
+	 * We don't know the TSC frequency yet, but waiting for
+	 * 40000000000/HZ TSC cycles is safe:
+	 * 4 GHz == 10 jiffies
+	 * 1 GHz == 40 jiffies
+	 */
+	do {
+		rep_nop();
+		now = rdtsc();
+	} while ((now - start) < 40000000000UL / HZ &&
+		time_before_eq(jiffies, ticks + 4));
+}
+
+static void delay_without_tsc(void)
+{
+	int band = 1;
+	unsigned long ticks = jiffies;
+
+	/*
+	 * We don't know any frequency yet, but waiting for
+	 * 40940000000/HZ cycles is safe:
+	 * 4 GHz == 10 jiffies
+	 * 1 GHz == 40 jiffies
+	 * 1 << 1 + 1 << 2 +...+ 1 << 11 = 4094
+	 */
+	do {
+		__delay(((1 << band++) * 10000000UL) / HZ);
+	} while (band < 12 && time_before_eq(jiffies, ticks + 4));
+}
+
+
 /*
  * There is a nasty bug in some older SMP boards, their mptable lies
  * about the timer IRQ. We do the following to work around the situation:
@@ -1625,8 +1663,12 @@ static int __init timer_irq_works(void)
 
 	local_save_flags(flags);
 	local_irq_enable();
-	/* Let ten ticks pass... */
-	mdelay((10 * 1000) / HZ);
+
+	if (boot_cpu_has(X86_FEATURE_TSC))
+		delay_with_tsc();
+	else
+		delay_without_tsc();
+
 	local_irq_restore(flags);
 
 	/*
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 06/12] x86/apic: Split local APIC timer setup from the APIC setup
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (4 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works() Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 07/12] x86/apic: Move the logical APIC ID setup from apic_bsp_setup() Dou Liyang
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

The apic_bsp_setup() set up the local APIC, I/O APIC and APIC timer.
The local APIC and I/O APIC setup belongs to interrupt delivery mode
setup. Setting up the local APIC timer for booting CPU is another job.

Unifying the interrupt delivery mode need setting the apic_bsp_setup()
in advance of calibrating TSC. but the APIC timer setup cannot be run
there.

Split local APIC timer setup from the APIC setup, keep it in the
original position for SMP and UP kernel.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/kernel/apic/apic.c | 4 ++--
 arch/x86/kernel/smpboot.c   | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 56be7f3..5f40d4a 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2357,8 +2357,6 @@ int __init apic_bsp_setup(bool upmode)
 	end_local_APIC_setup();
 	irq_remap_enable_fault_handling();
 	setup_IO_APIC();
-	/* Setup local timer */
-	x86_init.timers.setup_percpu_clockev();
 	return id;
 }
 
@@ -2398,6 +2396,8 @@ int __init APIC_init_uniprocessor(void)
 
 	default_setup_apic_routing();
 	apic_bsp_setup(true);
+	/* Setup local timer */
+	x86_init.timers.setup_percpu_clockev();
 	return 0;
 }
 
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index f04479a..e44f957 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1347,6 +1347,10 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	default_setup_apic_routing();
 	cpu0_logical_apicid = apic_bsp_setup(false);
 
+
+	/* Setup local timer */
+	x86_init.timers.setup_percpu_clockev();
+
 	pr_info("CPU0: ");
 	print_cpu_info(&cpu_data(0));
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 07/12] x86/apic: Move the logical APIC ID setup from apic_bsp_setup()
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (5 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 06/12] x86/apic: Split local APIC timer setup from the APIC setup Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 08/12] x86/apic: Make interrupt mode setup earlier for SMP-capable system Dou Liyang
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

The apic_bsp_setup() sets and returns logical APIC ID for setting up
cpu0_logical_apicid in SMP-capable system.

The id has nothing to do with the initialization of local APIC and
I/O APIC. And apic_bsp_setup() will be called earlier.

Move the id setup to native_smp_prepare_cpus() for cleanup.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/include/asm/apic.h |  2 +-
 arch/x86/kernel/apic/apic.c | 10 +---------
 arch/x86/kernel/smpboot.c   |  4 ++++
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index e9502e6..13f46e3 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -146,7 +146,7 @@ static inline int apic_force_enable(unsigned long addr)
 extern int apic_force_enable(unsigned long addr);
 #endif
 
-extern int apic_bsp_setup(bool upmode);
+extern void apic_bsp_setup(bool upmode);
 extern void apic_ap_setup(void);
 
 /*
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 5f40d4a..614ee6b 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2339,25 +2339,17 @@ static void __init apic_bsp_up_setup(void)
  * Returns:
  * apic_id of BSP APIC
  */
-int __init apic_bsp_setup(bool upmode)
+void __init apic_bsp_setup(bool upmode)
 {
-	int id;
-
 	connect_bsp_APIC();
 	if (upmode)
 		apic_bsp_up_setup();
 	setup_local_APIC();
 
-	if (x2apic_mode)
-		id = apic_read(APIC_LDR);
-	else
-		id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
-
 	enable_IO_APIC();
 	end_local_APIC_setup();
 	irq_remap_enable_fault_handling();
 	setup_IO_APIC();
-	return id;
 }
 
 /*
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index e44f957..4e706e7 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1347,6 +1347,10 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	default_setup_apic_routing();
 	cpu0_logical_apicid = apic_bsp_setup(false);
 
+	if (x2apic_mode)
+		cpu0_logical_apicid = apic_read(APIC_LDR);
+	else
+		cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
 
 	/* Setup local timer */
 	x86_init.timers.setup_percpu_clockev();
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 08/12] x86/apic: Make interrupt mode setup earlier for SMP-capable system
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (6 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 07/12] x86/apic: Move the logical APIC ID setup from apic_bsp_setup() Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 09/12] x86/apic: Setup interrupt mode earlier in case of no SMP motherboard Dou Liyang
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

In the SMP-capable system, enable and setup the interrupt delivery
mode in native_smp_prepare_cpus() which almost be called at the end of
start_kernel() in rest_init().

But, due to default mode may not be compatible with the actual interrupt
registers, calibrating delay which needs the timer IRQs may be failed
in dump-capture kernel.

The MP table or ACPI has been read earlier, setup the interrupt mode as
soon as possible, make the system run in the final mode to avoid the
compatibility issues.

Core patch for SMP-capable system.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/kernel/apic/apic.c | 21 +++++++++++++++++++++
 arch/x86/kernel/smpboot.c   | 10 ----------
 2 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 614ee6b..941ae1e 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1161,6 +1161,7 @@ enum apic_interrupt_mode {
 	APIC_PIC = 0,
 	APIC_VIRTUAL_WIRE,
 	APIC_SYMMETRIC_IO,
+	APIC_SYMMETRIC_IO_NO_ROUTING,
 	APIC_MODE_COUNT
 };
 
@@ -1215,6 +1216,20 @@ static int __init apic_interrupt_mode_select(void)
 
 	/* Other checks of APIC options will be done in each setup function */
 
+#ifdef CONFIG_SMP
+	if (read_apic_id() != boot_cpu_physical_apicid) {
+		panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
+		     read_apic_id(), boot_cpu_physical_apicid);
+		/* Or can we switch back to PIC here? */
+	}
+
+	/* If SMP should be disabled, then really disable it! */
+	if (!setup_max_cpus) {
+		pr_info("SMP mode deactivated\n");
+		return APIC_SYMMETRIC_IO_NO_ROUTING;
+	}
+#endif
+
 	return APIC_SYMMETRIC_IO;
 }
 
@@ -1279,6 +1294,12 @@ void __init apic_interrupt_mode_init(void)
 		return;
 	case APIC_SYMMETRIC_IO:
 		pr_info("Switch to symmectic I/O mode\n");
+		default_setup_apic_routing();
+		apic_bsp_setup(false);
+		return;
+	case APIC_SYMMETRIC_IO_NO_ROUTING:
+		pr_info("Switch to symmectic I/O mode with no APIC routing\n");
+		apic_bsp_setup(false);
 		return;
 	}
 }
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 4e706e7..2101d5c 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1332,21 +1332,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 		return;
 	case SMP_FORCE_UP:
 		disable_smp();
-		apic_bsp_setup(false);
 		return;
 	case SMP_OK:
 		break;
 	}
 
-	if (read_apic_id() != boot_cpu_physical_apicid) {
-		panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
-		     read_apic_id(), boot_cpu_physical_apicid);
-		/* Or can we switch back to PIC here? */
-	}
-
-	default_setup_apic_routing();
-	cpu0_logical_apicid = apic_bsp_setup(false);
-
 	if (x2apic_mode)
 		cpu0_logical_apicid = apic_read(APIC_LDR);
 	else
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 09/12] x86/apic: Setup interrupt mode earlier in case of no SMP motherboard
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (7 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 08/12] x86/apic: Make interrupt mode setup earlier for SMP-capable system Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-12  9:55   ` [RFC PATCH v4 " Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 10/12] x86/apic: Make the interrupt mode setup earlier for UP system Dou Liyang
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Kernel falls back to non SMP mode and sets up interrupt delivery mode
in APIC_init_uniprocessor() in case of no SMP motherboard.

Setting up interrupt delivery mode as soon as possible should wraps
this case for SMP-capable system too.

Wrap this case, make it consistent with SMP-capable systems.
Incidentally,
 -Extract apic_bsp_setup() and Refine apic_interrupt_mode_init().

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
v2 --> v3:
  Replace APIC_SYMMETRIC_IO_NO_CONFIG with APIC_VIRTUAL_WIRE_NO_CONFIG
  Do some cleanup.
 arch/x86/kernel/apic/apic.c | 23 ++++++++++++++++-------
 arch/x86/kernel/smpboot.c   |  2 --
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 941ae1e..b09650d 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1160,12 +1160,13 @@ void __init sync_Arb_IDs(void)
 enum apic_interrupt_mode {
 	APIC_PIC = 0,
 	APIC_VIRTUAL_WIRE,
+	APIC_VIRTUAL_WIRE_NO_CONFIG,
 	APIC_SYMMETRIC_IO,
 	APIC_SYMMETRIC_IO_NO_ROUTING,
 	APIC_MODE_COUNT
 };
 
-static int __init apic_interrupt_mode_select(void)
+static int __init apic_interrupt_mode_select(int *upmode)
 {
 	/* Check kernel option */
 	if (disable_apic) {
@@ -1208,8 +1209,12 @@ static int __init apic_interrupt_mode_select(void)
 	if (!smp_found_config) {
 		disable_ioapic_support();
 
-		if (!acpi_lapic)
+		if (!acpi_lapic) {
 			pr_info("ACPI MADT or MP table not detected\n");
+			*upmode = true;
+
+			return APIC_VIRTUAL_WIRE_NO_CONFIG;
+		}
 
 		return APIC_VIRTUAL_WIRE;
 	}
@@ -1285,23 +1290,27 @@ void __init apic_virtual_wire_mode_setup(void)
 /* Init the interrupt delivery mode for the BSP */
 void __init apic_interrupt_mode_init(void)
 {
-	switch (apic_interrupt_mode_select()) {
+	int upmode = false;
+
+	switch (apic_interrupt_mode_select(&upmode)) {
 	case APIC_PIC:
 		pr_info("Keep in PIC mode(8259)\n");
 		return;
 	case APIC_VIRTUAL_WIRE:
+	case APIC_VIRTUAL_WIRE_NO_CONFIG:
 		pr_info("Switch to virtual wire mode\n");
-		return;
+		default_setup_apic_routing();
+		break;
 	case APIC_SYMMETRIC_IO:
 		pr_info("Switch to symmectic I/O mode\n");
 		default_setup_apic_routing();
-		apic_bsp_setup(false);
-		return;
+		break;
 	case APIC_SYMMETRIC_IO_NO_ROUTING:
 		pr_info("Switch to symmectic I/O mode with no APIC routing\n");
-		apic_bsp_setup(false);
 		return;
 	}
+
+	apic_bsp_setup(upmode);
 }
 
 static void lapic_setup_esr(void)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 2101d5c..6e8c39b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1324,8 +1324,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	switch (smp_sanity_check(max_cpus)) {
 	case SMP_NO_CONFIG:
 		disable_smp();
-		if (APIC_init_uniprocessor())
-			pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
 		return;
 	case SMP_NO_APIC:
 		disable_smp();
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 10/12] x86/apic: Make the interrupt mode setup earlier for UP system
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (8 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 09/12] x86/apic: Setup interrupt mode earlier in case of no SMP motherboard Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-11 10:57   ` [RFC PATCH v4 " Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 11/12] x86/apic: Mark the apic_interrupt_mode extern for disable_smp() Dou Liyang
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

In UniProcessor kernel with UP_LATE_INIT=y, enable and setup the
interrupt delivery mode in smp_init() which almost be called at the
end of start_kernel().

But, system should not make sure the timer IRQs work well for
calibrating delay in dump-capture kernel.

Due to the MP table or ACPI has been read earlier, setup the interrupt
mode as soon as possible, and make the system run in the final mode to
avoid the compatibility issues.

Core patch for UP kernel and remove the original setup code.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
v2 --> v3:
  remove the APIC_init_uniprocessor()
 
 arch/x86/include/asm/apic.h |  1 -
 arch/x86/kernel/apic/apic.c | 49 ++++++---------------------------------------
 2 files changed, 6 insertions(+), 44 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 13f46e3..78a0c74 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -135,7 +135,6 @@ void register_lapic_address(unsigned long address);
 extern void setup_boot_APIC_clock(void);
 extern void setup_secondary_APIC_clock(void);
 extern void lapic_update_tsc_freq(void);
-extern int APIC_init_uniprocessor(void);
 
 #ifdef CONFIG_X86_64
 static inline int apic_force_enable(unsigned long addr)
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index b09650d..5fe98b9 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1233,9 +1233,12 @@ static int __init apic_interrupt_mode_select(int *upmode)
 		pr_info("SMP mode deactivated\n");
 		return APIC_SYMMETRIC_IO_NO_ROUTING;
 	}
+#else
+	/* UP_LATE_INIT is true */
+	*upmode = true;
 #endif
-
 	return APIC_SYMMETRIC_IO;
+
 }
 
 /*
@@ -2382,51 +2385,11 @@ void __init apic_bsp_setup(bool upmode)
 	setup_IO_APIC();
 }
 
-/*
- * This initializes the IO-APIC and APIC hardware if this is
- * a UP kernel.
- */
-int __init APIC_init_uniprocessor(void)
-{
-	if (disable_apic) {
-		pr_info("Apic disabled\n");
-		return -1;
-	}
-#ifdef CONFIG_X86_64
-	if (!boot_cpu_has(X86_FEATURE_APIC)) {
-		disable_apic = 1;
-		pr_info("Apic disabled by BIOS\n");
-		return -1;
-	}
-#else
-	if (!smp_found_config && !boot_cpu_has(X86_FEATURE_APIC))
-		return -1;
-
-	/*
-	 * Complain if the BIOS pretends there is one.
-	 */
-	if (!boot_cpu_has(X86_FEATURE_APIC) &&
-	    APIC_INTEGRATED(boot_cpu_apic_version)) {
-		pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
-			boot_cpu_physical_apicid);
-		return -1;
-	}
-#endif
-
-	if (!smp_found_config)
-		disable_ioapic_support();
-
-	default_setup_apic_routing();
-	apic_bsp_setup(true);
-	/* Setup local timer */
-	x86_init.timers.setup_percpu_clockev();
-	return 0;
-}
-
 #ifdef CONFIG_UP_LATE_INIT
 void __init up_late_init(void)
 {
-	APIC_init_uniprocessor();
+	/* Setup local APIC timer */
+	x86_init.timers.setup_percpu_clockev();
 }
 #endif
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 11/12] x86/apic: Mark the apic_interrupt_mode extern for disable_smp()
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (9 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 10/12] x86/apic: Make the interrupt mode setup earlier for UP system Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-10 13:44 ` [RFC PATCH v3 12/12] x86/apic: Remove the apic_virtual_wire_mode_setup() Dou Liyang
  2017-05-22 20:23 ` [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Thomas Gleixner
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Calling native_smp_prepare_cpus() to prepare for SMP bootup, does
some sanity checking, enables APIC mode and disables SMP feature.

Now, APIC mode setup has been unified to apic_interrupt_mode_init()
earlier, the sanity checking is redundant and need to be cleaned up.

Mark the apic_interrupt_mode extern to refine the switch and remove
the redundant sanity check.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/include/asm/apic.h |  9 +++++++++
 arch/x86/kernel/apic/apic.c | 12 +++--------
 arch/x86/kernel/smpboot.c   | 49 ++++++++-------------------------------------
 3 files changed, 20 insertions(+), 50 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 78a0c74..9f6ac51 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -53,6 +53,15 @@ extern int local_apic_timer_c2_ok;
 extern int disable_apic;
 extern unsigned int lapic_timer_frequency;
 
+extern enum apic_interrupt_mode_id apic_interrupt_mode;
+enum apic_interrupt_mode_id {
+	APIC_PIC = 0,
+	APIC_VIRTUAL_WIRE,
+	APIC_VIRTUAL_WIRE_NO_CONFIG,
+	APIC_SYMMETRIC_IO,
+	APIC_SYMMETRIC_IO_NO_ROUTING
+};
+
 #ifdef CONFIG_SMP
 extern void __inquire_remote_apic(int apicid);
 #else /* CONFIG_SMP */
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 5fe98b9..c2635bf 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1157,14 +1157,7 @@ void __init sync_Arb_IDs(void)
 			APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
-enum apic_interrupt_mode {
-	APIC_PIC = 0,
-	APIC_VIRTUAL_WIRE,
-	APIC_VIRTUAL_WIRE_NO_CONFIG,
-	APIC_SYMMETRIC_IO,
-	APIC_SYMMETRIC_IO_NO_ROUTING,
-	APIC_MODE_COUNT
-};
+enum apic_interrupt_mode_id apic_interrupt_mode;
 
 static int __init apic_interrupt_mode_select(int *upmode)
 {
@@ -1295,7 +1288,8 @@ void __init apic_interrupt_mode_init(void)
 {
 	int upmode = false;
 
-	switch (apic_interrupt_mode_select(&upmode)) {
+	apic_interrupt_mode = apic_interrupt_mode_select(&upmode);
+	switch (apic_interrupt_mode) {
 	case APIC_PIC:
 		pr_info("Keep in PIC mode(8259)\n");
 		return;
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6e8c39b..bc8f475 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1193,7 +1193,7 @@ enum {
 /*
  * Various sanity checks.
  */
-static int __init smp_sanity_check(unsigned max_cpus)
+static void __init smp_sanity_check(void)
 {
 	preempt_disable();
 
@@ -1231,16 +1231,6 @@ 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 && !acpi_lapic) {
-		preempt_enable();
-		pr_notice("SMP motherboard not detected\n");
-		return SMP_NO_CONFIG;
-	}
-
-	/*
 	 * Should not be necessary because the MP table should list the boot
 	 * CPU too, but we do it for the sake of robustness anyway.
 	 */
@@ -1250,29 +1240,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
 		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
 	}
 	preempt_enable();
-
-	/*
-	 * If we couldn't find a local APIC, then get out of here now!
-	 */
-	if (APIC_INTEGRATED(boot_cpu_apic_version) &&
-	    !boot_cpu_has(X86_FEATURE_APIC)) {
-		if (!disable_apic) {
-			pr_err("BIOS bug, local APIC #%d not detected!...\n",
-				boot_cpu_physical_apicid);
-			pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
-		}
-		return SMP_NO_APIC;
-	}
-
-	/*
-	 * If SMP should be disabled, then really disable it!
-	 */
-	if (!max_cpus) {
-		pr_info("SMP mode deactivated\n");
-		return SMP_FORCE_UP;
-	}
-
-	return SMP_OK;
 }
 
 static void __init smp_cpu_index_default(void)
@@ -1320,18 +1287,18 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	set_sched_topology(x86_topology);
 
 	set_cpu_sibling_map(0);
+	smp_sanity_check();
 
-	switch (smp_sanity_check(max_cpus)) {
-	case SMP_NO_CONFIG:
-		disable_smp();
-		return;
-	case SMP_NO_APIC:
+	switch (apic_interrupt_mode) {
+	case APIC_PIC:
+	case APIC_VIRTUAL_WIRE_NO_CONFIG:
 		disable_smp();
 		return;
-	case SMP_FORCE_UP:
+	case APIC_SYMMETRIC_IO_NO_ROUTING:
 		disable_smp();
+		x86_init.timers.setup_percpu_clockev();
 		return;
-	case SMP_OK:
+	default:
 		break;
 	}
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v3 12/12] x86/apic: Remove the apic_virtual_wire_mode_setup()
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (10 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 11/12] x86/apic: Mark the apic_interrupt_mode extern for disable_smp() Dou Liyang
@ 2017-05-10 13:44 ` Dou Liyang
  2017-05-22 20:23 ` [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Thomas Gleixner
  12 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-10 13:44 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Currently, enable and setup the interrupt mode has been advanced
just behind the timer IRQ setup. It can setup the virtual wire
mode if the system select it. and it also can switch to the final
mode from PIC mode directly.

The apic_virtual_wire_mode_setup() which works for the virtual wire
mode is redundant.

Remove the apic_virtual_wire_mode_setup() function.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
 arch/x86/include/asm/apic.h |  2 --
 arch/x86/kernel/apic/apic.c | 49 ---------------------------------------------
 arch/x86/kernel/irqinit.c   |  2 --
 3 files changed, 53 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 9f6ac51..0af0da0 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -136,7 +136,6 @@ extern void disconnect_bsp_APIC(int virt_wire_setup);
 extern void disable_local_APIC(void);
 extern void lapic_shutdown(void);
 extern void sync_Arb_IDs(void);
-extern void apic_virtual_wire_mode_setup(void);
 extern void apic_interrupt_mode_init(void);
 extern void setup_local_APIC(void);
 extern void init_apic_mappings(void);
@@ -179,7 +178,6 @@ static inline void disable_local_APIC(void) { }
 # define setup_boot_APIC_clock x86_init_noop
 # define setup_secondary_APIC_clock x86_init_noop
 static inline void lapic_update_tsc_freq(void) { }
-static inline void apic_virtual_wire_mode_setup(void) {}
 static inline void apic_interrupt_mode_init(void) {}
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index c2635bf..3000d90 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1234,55 +1234,6 @@ static int __init apic_interrupt_mode_select(int *upmode)
 
 }
 
-/*
- * Setup the through-local-APIC virtual wire mode.
- */
-void __init apic_virtual_wire_mode_setup(void)
-{
-	unsigned int value;
-
-	/*
-	 * Don't do the setup now if we have a SMP BIOS as the
-	 * through-I/O-APIC virtual wire mode might be active.
-	 */
-	if (smp_found_config || !boot_cpu_has(X86_FEATURE_APIC))
-		return;
-
-	/*
-	 * Do not trust the local APIC being empty at bootup.
-	 */
-	clear_local_APIC();
-
-	/*
-	 * Enable APIC.
-	 */
-	value = apic_read(APIC_SPIV);
-	value &= ~APIC_VECTOR_MASK;
-	value |= APIC_SPIV_APIC_ENABLED;
-
-#ifdef CONFIG_X86_32
-	/* This bit is reserved on P4/Xeon and should be cleared */
-	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-	    (boot_cpu_data.x86 == 15))
-		value &= ~APIC_SPIV_FOCUS_DISABLED;
-	else
-#endif
-		value |= APIC_SPIV_FOCUS_DISABLED;
-	value |= SPURIOUS_APIC_VECTOR;
-	apic_write(APIC_SPIV, value);
-
-	/*
-	 * Set up the virtual wire mode.
-	 */
-	apic_write(APIC_LVT0, APIC_DM_EXTINT);
-	value = APIC_DM_NMI;
-	if (!lapic_is_integrated())		/* 82489DX */
-		value |= APIC_LVT_LEVEL_TRIGGER;
-	if (apic_extnmi == APIC_EXTNMI_NONE)
-		value |= APIC_LVT_MASKED;
-	apic_write(APIC_LVT1, value);
-}
-
 /* Init the interrupt delivery mode for the BSP */
 void __init apic_interrupt_mode_init(void)
 {
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index e4f89b6..488c9e2 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -72,8 +72,6 @@ void __init init_ISA_irqs(void)
 	struct irq_chip *chip = legacy_pic->chip;
 	int i;
 
-	apic_virtual_wire_mode_setup();
-
 	legacy_pic->init(0);
 
 	for (i = 0; i < nr_legacy_irqs(); i++)
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v4 10/12] x86/apic: Make the interrupt mode setup earlier for UP system
  2017-05-10 13:44 ` [RFC PATCH v3 10/12] x86/apic: Make the interrupt mode setup earlier for UP system Dou Liyang
@ 2017-05-11 10:57   ` Dou Liyang
  0 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-11 10:57 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

In UniProcessor kernel with UP_LATE_INIT=y, enable and setup the
interrupt delivery mode in smp_init() which almost be called at the
end of start_kernel().

But, system should not make sure the timer IRQs work well for
calibrating delay in dump-capture kernel.

Due to the MP table or ACPI has been read earlier, setup the interrupt
mode as soon as possible, and make the system run in the final mode to
avoid the compatibility issues.

Core patch for UP kernel and remove the original setup code.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
V3 --> V4:
  - Setup upmode earlier for UP system.
  - Check interrupt mode before per cpu clock event setup.

 arch/x86/include/asm/apic.h |  1 -
 arch/x86/kernel/apic/apic.c | 49 ++++++++-------------------------------------
 2 files changed, 8 insertions(+), 42 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 13f46e3..78a0c74 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -135,7 +135,6 @@ void register_lapic_address(unsigned long address);
 extern void setup_boot_APIC_clock(void);
 extern void setup_secondary_APIC_clock(void);
 extern void lapic_update_tsc_freq(void);
-extern int APIC_init_uniprocessor(void);
 
 #ifdef CONFIG_X86_64
 static inline int apic_force_enable(unsigned long addr)
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index b09650d..304b050 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1205,6 +1205,10 @@ static int __init apic_interrupt_mode_select(int *upmode)
 	}
 #endif
 
+#ifdef CONFIG_UP_LATE_INIT
+	*upmode = true;
+#endif
+
 	/* Check MP table or ACPI MADT configuration */
 	if (!smp_found_config) {
 		disable_ioapic_support();
@@ -2382,51 +2386,14 @@ void __init apic_bsp_setup(bool upmode)
 	setup_IO_APIC();
 }
 
-/*
- * This initializes the IO-APIC and APIC hardware if this is
- * a UP kernel.
- */
-int __init APIC_init_uniprocessor(void)
+#ifdef CONFIG_UP_LATE_INIT
+void __init up_late_init(void)
 {
-	if (disable_apic) {
-		pr_info("Apic disabled\n");
-		return -1;
-	}
-#ifdef CONFIG_X86_64
-	if (!boot_cpu_has(X86_FEATURE_APIC)) {
-		disable_apic = 1;
-		pr_info("Apic disabled by BIOS\n");
-		return -1;
-	}
-#else
-	if (!smp_found_config && !boot_cpu_has(X86_FEATURE_APIC))
-		return -1;
-
-	/*
-	 * Complain if the BIOS pretends there is one.
-	 */
-	if (!boot_cpu_has(X86_FEATURE_APIC) &&
-	    APIC_INTEGRATED(boot_cpu_apic_version)) {
-		pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
-			boot_cpu_physical_apicid);
-		return -1;
-	}
-#endif
-
-	if (!smp_found_config)
-		disable_ioapic_support();
+	if (apic_interrupt_mode == APIC_PIC)
+		return;
 
-	default_setup_apic_routing();
-	apic_bsp_setup(true);
 	/* Setup local timer */
 	x86_init.timers.setup_percpu_clockev();
-	return 0;
-}
-
-#ifdef CONFIG_UP_LATE_INIT
-void __init up_late_init(void)
-{
-	APIC_init_uniprocessor();
 }
 #endif
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v4 09/12] x86/apic: Setup interrupt mode earlier in case of no SMP motherboard
  2017-05-10 13:44 ` [RFC PATCH v3 09/12] x86/apic: Setup interrupt mode earlier in case of no SMP motherboard Dou Liyang
@ 2017-05-12  9:55   ` Dou Liyang
  0 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-12  9:55 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Kernel falls back to non SMP mode and sets up interrupt delivery mode
in APIC_init_uniprocessor() in case of no SMP motherboard.

Setting up interrupt delivery mode as soon as possible should wraps
this case for SMP-capable system too.

Wrap this case, make it consistent with SMP-capable systems.
Incidentally,
 -Extract apic_bsp_setup() and Refine apic_interrupt_mode_init().

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
Sorry to trouble again, I tested a bug, update the patch to fix it.

V3 --> V4:
  - Replace "return" with "break" in case of APIC_SYMMETRIC_IO_NO_ROUTING

V2 --> V3:
  - Replace APIC_SYMMETRIC_IO_NO_CONFIG with APIC_VIRTUAL_WIRE_NO_CONFIG
  - Do some cleanup.

 arch/x86/kernel/apic/apic.c | 25 +++++++++++++++++--------
 arch/x86/kernel/smpboot.c   |  2 --
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 941ae1e..1c93c65 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1160,12 +1160,13 @@ void __init sync_Arb_IDs(void)
 enum apic_interrupt_mode {
 	APIC_PIC = 0,
 	APIC_VIRTUAL_WIRE,
+	APIC_VIRTUAL_WIRE_NO_CONFIG,
 	APIC_SYMMETRIC_IO,
 	APIC_SYMMETRIC_IO_NO_ROUTING,
 	APIC_MODE_COUNT
 };
 
-static int __init apic_interrupt_mode_select(void)
+static int __init apic_interrupt_mode_select(int *upmode)
 {
 	/* Check kernel option */
 	if (disable_apic) {
@@ -1208,8 +1209,12 @@ static int __init apic_interrupt_mode_select(void)
 	if (!smp_found_config) {
 		disable_ioapic_support();
 
-		if (!acpi_lapic)
+		if (!acpi_lapic) {
 			pr_info("ACPI MADT or MP table not detected\n");
+			*upmode = true;
+
+			return APIC_VIRTUAL_WIRE_NO_CONFIG;
+		}
 
 		return APIC_VIRTUAL_WIRE;
 	}
@@ -1285,23 +1290,27 @@ void __init apic_virtual_wire_mode_setup(void)
 /* Init the interrupt delivery mode for the BSP */
 void __init apic_interrupt_mode_init(void)
 {
-	switch (apic_interrupt_mode_select()) {
+	int upmode = false;
+
+	switch (apic_interrupt_mode_select(&upmode)) {
 	case APIC_PIC:
 		pr_info("Keep in PIC mode(8259)\n");
 		return;
 	case APIC_VIRTUAL_WIRE:
+	case APIC_VIRTUAL_WIRE_NO_CONFIG:
 		pr_info("Switch to virtual wire mode\n");
-		return;
+		default_setup_apic_routing();
+		break;
 	case APIC_SYMMETRIC_IO:
 		pr_info("Switch to symmectic I/O mode\n");
 		default_setup_apic_routing();
-		apic_bsp_setup(false);
-		return;
+		break;
 	case APIC_SYMMETRIC_IO_NO_ROUTING:
 		pr_info("Switch to symmectic I/O mode with no APIC routing\n");
-		apic_bsp_setup(false);
-		return;
+		break;
 	}
+
+	apic_bsp_setup(upmode);
 }
 
 static void lapic_setup_esr(void)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 2101d5c..6e8c39b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1324,8 +1324,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	switch (smp_sanity_check(max_cpus)) {
 	case SMP_NO_CONFIG:
 		disable_smp();
-		if (APIC_init_uniprocessor())
-			pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
 		return;
 	case SMP_NO_APIC:
 		disable_smp();
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
  2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
                   ` (11 preceding siblings ...)
  2017-05-10 13:44 ` [RFC PATCH v3 12/12] x86/apic: Remove the apic_virtual_wire_mode_setup() Dou Liyang
@ 2017-05-22 20:23 ` Thomas Gleixner
  2017-05-23  1:29   ` Dou Liyang
  2017-06-26 10:08   ` Dou Liyang
  12 siblings, 2 replies; 23+ messages in thread
From: Thomas Gleixner @ 2017-05-22 20:23 UTC (permalink / raw)
  To: Dou Liyang; +Cc: x86, linux-kernel, mingo, hpa, ebiederm, bhe, izumi.taku

Dou,

On Wed, 10 May 2017, Dou Liyang wrote:

> According to Ingo's and Eric's advice[1,2], Try my best to optimize the 
> init of interrupt delivery mode for x86.

sorry for replying late. The patchset is not forgotten, it's on my todo
list and I'll tend to it latest next week.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
  2017-05-22 20:23 ` [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Thomas Gleixner
@ 2017-05-23  1:29   ` Dou Liyang
  2017-06-06  6:50     ` Dou Liyang
  2017-06-26 10:08   ` Dou Liyang
  1 sibling, 1 reply; 23+ messages in thread
From: Dou Liyang @ 2017-05-23  1:29 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: x86, linux-kernel, mingo, hpa, ebiederm, bhe, izumi.taku

Dear Thomas,

At 05/23/2017 04:23 AM, Thomas Gleixner wrote:
> Dou,
>
> On Wed, 10 May 2017, Dou Liyang wrote:
>
>> According to Ingo's and Eric's advice[1,2], Try my best to optimize the
>> init of interrupt delivery mode for x86.
>
> sorry for replying late. The patchset is not forgotten, it's on my todo
> list and I'll tend to it latest next week.
>

I am very glad to hear that. :)

I will check it again and wait for your advice.

Thanks,
   Liyang.

> Thanks,
>
> 	tglx
>
>
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [RFC PATCH v4 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works()
  2017-05-10 13:44 ` [RFC PATCH v3 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works() Dou Liyang
@ 2017-05-26  8:10   ` Dou Liyang
  0 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-05-26  8:10 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

Kernel use timer_irq_works() to detects the timer IRQs. It calls
mdelay(10) to delay ten ticks and checks whether the timer IRQs work
or not. The mdelay() depends on the loops_per_jiffy which is set up
in calibrate_delay(). But in "notsc" case, calibrating delay also
should make sure the timer IRQs work well. There need each other.

Current kernel defaults the IRQs is available when it calibrates delay.
But it is wrong in the dump-capture kernel with 'notsc' option inherited
from 1st kernel option. The correct design is making the interrupt mode
setup and checking IRQs works in advance of calibrate_delay(). That results
in the mdelay() being unusable in timer_irq_works().

Refactor the delay logic by waiting for some cycles. In the system with
X86_FEATURE_TSC feature, Use rdtsc(), others will call __delay() directly.

Note: regard 4G as the max CPU frequence of current single CPU.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---

V3 --> V4:
  -Rewrite the changelog
  -Delete a blank line
v2 --> v3:
  -Find a new way to for waiting.
  -Reference to the realization of hpet_clocksource_register() by Thomas.

 arch/x86/kernel/apic/io_apic.c | 45 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 347bb9f..f710077 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1607,6 +1607,43 @@ static int __init notimercheck(char *s)
 }
 __setup("no_timer_check", notimercheck);
 
+static void __init delay_with_tsc(void)
+{
+	unsigned long long start, now;
+	unsigned long ticks = jiffies;
+
+	start = rdtsc();
+
+	/*
+	 * We don't know the TSC frequency yet, but waiting for
+	 * 40000000000/HZ TSC cycles is safe:
+	 * 4 GHz == 10 jiffies
+	 * 1 GHz == 40 jiffies
+	 */
+	do {
+		rep_nop();
+		now = rdtsc();
+	} while ((now - start) < 40000000000UL / HZ &&
+		time_before_eq(jiffies, ticks + 4));
+}
+
+static void __init delay_without_tsc(void)
+{
+	int band = 1;
+	unsigned long ticks = jiffies;
+
+	/*
+	 * We don't know any frequency yet, but waiting for
+	 * 40940000000/HZ cycles is safe:
+	 * 4 GHz == 10 jiffies
+	 * 1 GHz == 40 jiffies
+	 * 1 << 1 + 1 << 2 +...+ 1 << 11 = 4094
+	 */
+	do {
+		__delay(((1 << band++) * 10000000UL) / HZ);
+	} while (band < 12 && time_before_eq(jiffies, ticks + 4));
+}
+
 /*
  * There is a nasty bug in some older SMP boards, their mptable lies
  * about the timer IRQ. We do the following to work around the situation:
@@ -1625,8 +1662,12 @@ static int __init timer_irq_works(void)
 
 	local_save_flags(flags);
 	local_irq_enable();
-	/* Let ten ticks pass... */
-	mdelay((10 * 1000) / HZ);
+
+	if (boot_cpu_has(X86_FEATURE_TSC))
+		delay_with_tsc();
+	else
+		delay_without_tsc();
+
 	local_irq_restore(flags);
 
 	/*
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH v4 04/12] x86/time: Initialize interrupt mode behind timer init
  2017-05-10 13:44 ` [RFC PATCH v3 04/12] x86/time: Initialize interrupt mode behind timer init Dou Liyang
@ 2017-06-06  6:00   ` Dou Liyang
  0 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-06-06  6:00 UTC (permalink / raw)
  To: x86, linux-kernel; +Cc: tglx, mingo, hpa, ebiederm, bhe, izumi.taku, Dou Liyang

In start_kernel(), firstly, it works on the default interrupy mode, then
switch to the final mode. Normally, Booting with BIOS reset is OK.

But, At dump-capture kernel, it boot up without BIOS reset, default mode
may not be compatible with the actual registers, that causes the delivery
interrupt to fail.

Try to set up the final mode as soon as possible. according to the parts
which split from that initialization:

1) Set up the APIC/IOAPIC (including testing whether the timer
   interrupt works)

2) Calibrate TSC

3) Set up the local APIC timer

-- From Thomas Gleixner

Initializing the mode should be earlier than calibrating TSC as soon as
possible and needs testing whether the timer interrupt works at the same
time.

Add interrupt_mode_init to x86_init_ops, and call it behind timers init,
which meets the above conditions.

Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com>
---
V3 --> V4:
  -Move interrupt_mode_init to x86_init_ops instead of the use of header
files

 arch/x86/include/asm/x86_init.h | 2 ++
 arch/x86/kernel/time.c          | 7 +++++++
 arch/x86/kernel/x86_init.c      | 1 +
 3 files changed, 10 insertions(+)

diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 7ba7e90..ce8a712 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -50,11 +50,13 @@ struct x86_init_resources {
  *				are set up.
  * @intr_init:			interrupt init code
  * @trap_init:			platform specific trap setup
+ * @interrupt_mode_init:	interrupt delivery mode setup
  */
 struct x86_init_irqs {
 	void (*pre_vector_init)(void);
 	void (*intr_init)(void);
 	void (*trap_init)(void);
+	void (*interrupt_mode_init)(void);
 };
 
 /**
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index d39c091..bbf2821 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -84,6 +84,13 @@ void __init hpet_time_init(void)
 static __init void x86_late_time_init(void)
 {
 	x86_init.timers.timer_init();
+
+	/*
+	 * After PIT/HPET timers init, select and setup
+	 * the final interrupt mode for delivering IRQs.
+	 */
+	x86_init.irqs.interrupt_mode_init();
+
 	tsc_init();
 }
 
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index a088b2c..bcb3173 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -55,6 +55,7 @@ struct x86_init_ops x86_init __initdata = {
 		.pre_vector_init	= init_ISA_irqs,
 		.intr_init		= native_init_IRQ,
 		.trap_init		= x86_init_noop,
+		.interrupt_mode_init	= apic_interrupt_mode_init
 	},
 
 	.oem = {
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
  2017-05-23  1:29   ` Dou Liyang
@ 2017-06-06  6:50     ` Dou Liyang
  0 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-06-06  6:50 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: x86, linux-kernel, mingo, hpa, ebiederm, bhe, izumi.taku

Hi Thomas,

At 05/23/2017 09:29 AM, Dou Liyang wrote:
> Dear Thomas,
>
> At 05/23/2017 04:23 AM, Thomas Gleixner wrote:
>> Dou,
>>
>> On Wed, 10 May 2017, Dou Liyang wrote:
>>
>>> According to Ingo's and Eric's advice[1,2], Try my best to optimize the
>>> init of interrupt delivery mode for x86.
>>
>> sorry for replying late. The patchset is not forgotten, it's on my todo
>> list and I'll tend to it latest next week.
>>
>
> I am very glad to hear that. :)
>
> I will check it again and wait for your advice.

I have come to a code bottleneck. Hope to spend your precious time and
let me move on.

Following is some test results for that patchset.

In a theoretical code analysis, the patchset can wrap the original
logic.

1) The original logic of the interrupt delivery mode setup:

-Step O_1) Keep in PIC mode or virtual wire mode:

   Check (smp_found_config || !boot_cpu_has(X86_FEATURE_APIC))
     true:  PIC mode
     false: virtual wire mode

-Step O_2) Try to switch to symmetric IO mode:
   O_2_1) In up system:

     -Check disable_apic
       ture: *O_S_1* (original situation 1)
     -Check whether there is a separate or integrated chip
       don't has: *O_S_2*
     -Check !smp_found_config
       ture: *O_S_3*
     -Others:
       *O_S_4*

   O_2_2) In smp-capable system:

     -Check !smp_found_config && !acpi_lapic
       true: goto *O_2_1)*
     -Check if it is LAPIC
       don't has: *O_S_5*
     -Check !max_cpus
       true: *O_S_6*
     -read_apic_id() != boot_cpu_physical_apicid
       true: *O_S_7*
     -Others:
             *O_S_8*

2) After that patchset, the new logic:

-Step N_1) Skip step O_1 and try to switch to the final interrupt mode
    -Check disable_apic
      ture: *N_S_1* (New situation 1)
    -Check whether there is a separate or integrated chip
      ture: *N_S_2*
    -Check if (!smp_found_config)
      ture: *N_S_3*
    -Check !setup_max_cpus
      ture: *N_S_4*
    -Check read_apic_id() != boot_cpu_physical_apicid
      ture: *N_S_5*
    -Others:
            *N_S_6*

O_S_1 is covered in N_S_1
O_S_2 is covered in N_S_2
O_S_3 is covered in N_S_3
O_S_4 is covered in N_S_6
O_S_5 is covered in N_S_2
O_S_6 is covered in N_S_4
O_S_7 is covered in N_S_5
O_S_8 is covered in N_S_6

--------------------------------------------

In the actual test, It also can work well in the situations of my test
matrix

The factors of test matrix:

  X86  | SMP |LOCAL APIC|I/O APIC|UP_LATE_INIT|
----- |-----|----------|--------|------------|
32-bit|  Y  |     Y    |    Y   |     Y      |
64-bit|  N  |     N    |    N   |     N      |

disable_apic|X86_FEATURE_APIC|smp_found_config|
------------|----------------|----------------|
       0     |        0       |        0       |
       1     |        1       |        1       |

acpi_lapic|acpi_ioapic|setup_max_cpus|
----------|-----------|--------------|
      0    |     0     |      =0      |
      1    |     1     |      >0      |
>
> Thanks,
>   Liyang.
>
>> Thanks,
>>
>>     tglx
>>
>>
>>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
  2017-05-22 20:23 ` [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Thomas Gleixner
  2017-05-23  1:29   ` Dou Liyang
@ 2017-06-26 10:08   ` Dou Liyang
  2017-06-26 11:50     ` Thomas Gleixner
  1 sibling, 1 reply; 23+ messages in thread
From: Dou Liyang @ 2017-06-26 10:08 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: x86, linux-kernel, mingo, hpa, ebiederm, bhe, izumi.taku

Hi Thomas,

At 05/23/2017 04:23 AM, Thomas Gleixner wrote:
> Dou,
>
> On Wed, 10 May 2017, Dou Liyang wrote:
>
>> According to Ingo's and Eric's advice[1,2], Try my best to optimize the
>> init of interrupt delivery mode for x86.
>
> sorry for replying late. The patchset is not forgotten, it's on my todo
> list and I'll tend to it latest next week.


I hope to know the status of this patchest in your todo list.

If you haven't dealt with it yet, I want to resent it as V5 first for
you:

   * rebase this patchset to upstream
   * remove the RFC presix
   * remove the 1/12 patch
   * replace the pr_info with apic_printk

Look forward to your reply !

Thanks,
	Dou.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
  2017-06-26 10:08   ` Dou Liyang
@ 2017-06-26 11:50     ` Thomas Gleixner
  2017-06-27  1:50       ` Dou Liyang
  0 siblings, 1 reply; 23+ messages in thread
From: Thomas Gleixner @ 2017-06-26 11:50 UTC (permalink / raw)
  To: Dou Liyang; +Cc: x86, linux-kernel, mingo, hpa, ebiederm, bhe, izumi.taku

Dou,

On Mon, 26 Jun 2017, Dou Liyang wrote:
> I hope to know the status of this patchest in your todo list.

I still did not come around to it.

> If you haven't dealt with it yet, I want to resent it as V5 first for
> you:
> 
>   * rebase this patchset to upstream
>   * remove the RFC presix
>   * remove the 1/12 patch
>   * replace the pr_info with apic_printk

That would be appreciated. It's going to move on top of my list, but not
before mid of next week.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible
  2017-06-26 11:50     ` Thomas Gleixner
@ 2017-06-27  1:50       ` Dou Liyang
  0 siblings, 0 replies; 23+ messages in thread
From: Dou Liyang @ 2017-06-27  1:50 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: x86, linux-kernel, mingo, hpa, ebiederm, bhe, izumi.taku

Hi Thomas,

At 06/26/2017 07:50 PM, Thomas Gleixner wrote:
> Dou,
>
> On Mon, 26 Jun 2017, Dou Liyang wrote:
>> I hope to know the status of this patchest in your todo list.
>
> I still did not come around to it.
>
>> If you haven't dealt with it yet, I want to resent it as V5 first for
>> you:
>>
>>   * rebase this patchset to upstream
>>   * remove the RFC presix
>>   * remove the 1/12 patch
>>   * replace the pr_info with apic_printk
>
> That would be appreciated. It's going to move on top of my list, but not
> before mid of next week.
>

Oh, Thank you for your prompt reply.

I know now.

   Thanks,

	Liyang.

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2017-06-27  1:50 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-10 13:44 [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 01/12] x86/apic: Replace init_bsp_APIC() with apic_virtual_wire_mode_setup() Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 02/12] x86/apic: Construct a selector for the interrupt delivery mode Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 03/12] x86/apic: Prepare for unifying the interrupt delivery modes setup Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 04/12] x86/time: Initialize interrupt mode behind timer init Dou Liyang
2017-06-06  6:00   ` [RFC PATCH v4 " Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works() Dou Liyang
2017-05-26  8:10   ` [RFC PATCH v4 " Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 06/12] x86/apic: Split local APIC timer setup from the APIC setup Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 07/12] x86/apic: Move the logical APIC ID setup from apic_bsp_setup() Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 08/12] x86/apic: Make interrupt mode setup earlier for SMP-capable system Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 09/12] x86/apic: Setup interrupt mode earlier in case of no SMP motherboard Dou Liyang
2017-05-12  9:55   ` [RFC PATCH v4 " Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 10/12] x86/apic: Make the interrupt mode setup earlier for UP system Dou Liyang
2017-05-11 10:57   ` [RFC PATCH v4 " Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 11/12] x86/apic: Mark the apic_interrupt_mode extern for disable_smp() Dou Liyang
2017-05-10 13:44 ` [RFC PATCH v3 12/12] x86/apic: Remove the apic_virtual_wire_mode_setup() Dou Liyang
2017-05-22 20:23 ` [RFC PATCH v3 00/12] Unify interrupt mode and setup it as soon as possible Thomas Gleixner
2017-05-23  1:29   ` Dou Liyang
2017-06-06  6:50     ` Dou Liyang
2017-06-26 10:08   ` Dou Liyang
2017-06-26 11:50     ` Thomas Gleixner
2017-06-27  1:50       ` Dou Liyang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).