From patchwork Thu Aug 1 16:32:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Woodhouse X-Patchwork-Id: 13750737 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E2D491B4C48; Thu, 1 Aug 2024 16:32:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722529970; cv=none; b=s5iMvNij/Xilh6jEiASpz5SYBQ+lss+fsBh+1yrZMEAJJWbg3FUnbZNB9282FQzgSePK4i4xmJ/35QmwaYSEl8VchMHCyNcb7I/zwnbeNMxfXhaRoMT2VjYqm6LPH1x4eucXiB9pEt62/cRzEsZfHcuWqyeJdAZmEysp4N3dbYI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722529970; c=relaxed/simple; bh=ZavNK65scCND+gSI7O4Bi4SDz7LIV99Qku5RqYvP+0Y=; h=Message-ID:Subject:From:To:Cc:Date:Content-Type:MIME-Version; b=GDrz0D54vPQYXQK/OsLXG2wjHORMH4TUQqNNIImm/XkjZoWhcHK16zeuf9Xafw8H6Xib0ApZPbGAq5OX8X4lZBOyckdqtigReRDtkMgigLzPQhRjcGAXfKSvrETRghvHwU2g80+gpR4P457u91SyzwDhUIjy+PcrARX53tdM34U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=s0VBKFXm; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="s0VBKFXm" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=MIME-Version:Content-Type:Date:Cc:To: From:Subject:Message-ID:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:In-Reply-To:References; bh=fWt1dkutceKExJIVkktLRrf0RXSuNUtxAecZS3Fh5Z0=; b=s0VBKFXmKih4kq+LZSM4E993Uw Pm5BTAxgaYKM83nXMHRCvLr4fhhEMf2GmE+vTxX2iowkoIU0eCH93/uxTNFQcO3UN21rLntJ+rim6 +v+yQXlyqhU84PBsMeKJdK3BfT2AFSjVN3xg9aQ/W4IGvUM08UjiXqOvEKaI1B3QL8EDHUaaAcPHG fyNTOZu8JSeYMTK9NBCagjkWtIrEEaGfbhOGYbFkUZVAZjYpcKyecxx7Lu23XX1Ha2BkuxK8S2ugj UxMnabpcXa3d1+z+AiJdEXiRDv186gSuaN4eC5y1Z++IzplSIYd0W6neH7047Y2zHpXiTmZJzli1t 4NubKP6A==; Received: from [2001:8b0:10b:5:9c27:6796:c1af:9131] (helo=u3832b3a9db3152.ant.amazon.com) by casper.infradead.org with esmtpsa (Exim 4.97.1 #2 (Red Hat Linux)) id 1sZYjJ-000000004KK-14Y1; Thu, 01 Aug 2024 16:32:41 +0000 Message-ID: <6cd62b5058e11a6262cb2e798cc85cc5daead3b1.camel@infradead.org> Subject: [PATCH] i8253: Disable PIT timer 0 when not in use From: David Woodhouse To: bp@alien8.de, dave.hansen@linux.intel.com, decui@microsoft.com, haiyangz@microsoft.com, kys@microsoft.com, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, lirongqing@baidu.com, mingo@redhat.com, seanjc@google.com, tglx@linutronix.de, wei.liu@kernel.org, x86 Cc: mikelley@microsoft.com, kvm , Daniel Lezcano Date: Thu, 01 Aug 2024 17:32:40 +0100 User-Agent: Evolution 3.44.4-0ubuntu2 Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html From: David Woodhouse Leaving the PIT interrupt running can cause noticeable steal time for virtual guests. The VMM generally has a timer which toggles the IRQ input to the PIC and I/O APIC, which takes CPU time away from the guest. Make sure it's turned off if it isn't going to be used. Except on real hardware, because the less we change on real hardware the better. There be dragons. Signed-off-by: David Woodhouse --- arch/x86/kernel/i8253.c | 13 +++++++++++-- drivers/clocksource/i8253.c | 30 ++++++++++++++++++++++++++---- include/linux/i8253.h | 1 + 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index 2b7999a1a50a..54bfbd2aa773 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -39,9 +40,17 @@ static bool __init use_pit(void) bool __init pit_timer_init(void) { - if (!use_pit()) - return false; + if (!use_pit()) { + /* + * Don't just ignore the PIT. Ensure it's stopped, because + * VMMs otherwise steal CPU time just to pointlessly waggle + * the (masked) IRQ. + */ + if (!hypervisor_is_type(X86_HYPER_NATIVE)) + clockevent_i8253_disable(); + return false; + } clockevent_i8253_init(true); global_clock_event = &i8253_clockevent; return true; diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c index d4350bb10b83..51aab0a74481 100644 --- a/drivers/clocksource/i8253.c +++ b/drivers/clocksource/i8253.c @@ -108,21 +108,43 @@ int __init clocksource_i8253_init(void) #endif #ifdef CONFIG_CLKEVT_I8253 -static int pit_shutdown(struct clock_event_device *evt) +void clockevent_i8253_disable(void) { - if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt)) - return 0; - raw_spin_lock(&i8253_lock); outb_p(0x30, PIT_MODE); + /* + * The spec is a little bit ambiguous, although it does say that + * "The actual order of the programming is quite flexible. Writing + * out of the MODE control word can be in any sequence of counter + * selection". + * + * Implementations differ, however, in whether a mode change takes + * effect immediately or whether it only occurs when the counter is + * subsequently written. The KVM in-kernel and AWS Nitro hypervisor + * implementations need the counter to be written; QEMU does not. + * + * Theoretically, in one-shot mode, writing the counter will cause + * the IRQ to trigger one last time before falling quiet. Allegedly, + * under Hyper-V it keeps firing repeatedly, thus the existence of + * the i8253_clear_counter_on_shutdown quick to refrain from doing + * so. + */ if (i8253_clear_counter_on_shutdown) { outb_p(0, PIT_CH0); outb_p(0, PIT_CH0); } raw_spin_unlock(&i8253_lock); +} + +static int pit_shutdown(struct clock_event_device *evt) +{ + if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt)) + return 0; + + clockevent_i8253_disable(); return 0; } diff --git a/include/linux/i8253.h b/include/linux/i8253.h index 8336b2f6f834..bf169cfef7f1 100644 --- a/include/linux/i8253.h +++ b/include/linux/i8253.h @@ -24,6 +24,7 @@ extern raw_spinlock_t i8253_lock; extern bool i8253_clear_counter_on_shutdown; extern struct clock_event_device i8253_clockevent; extern void clockevent_i8253_init(bool oneshot); +extern void clockevent_i8253_disable(void); extern void setup_pit_timer(void);