lkml.org 
[lkml]   [2017]   [May]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH v4 05/12] x86/ioapic: Refactor the delay logic in timer_irq_works()
    Date
    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


    \
     
     \ /
      Last update: 2017-05-26 10:14    [W:3.155 / U:0.044 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site