From: Marcelo Tosatti <mtosatti@redhat.com>
To: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: "Joao Martins" <joao.m.martins@oracle.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
kvm-devel <kvm@vger.kernel.org>,
"Linux Kernel Mailing List" <linux-kernel@vger.kernel.org>,
"Radim Krčmář" <rkrcmar@redhat.com>,
"Sean Christopherson" <sean.j.christopherson@intel.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Wanpeng Li" <wanpengli@tencent.com>,
"Jim Mattson" <jmattson@google.com>,
"Joerg Roedel" <joro@8bytes.org>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>,
"Daniel Lezcano" <daniel.lezcano@linaro.org>,
"Linux PM" <linux-pm@vger.kernel.org>,
"Boris Ostrovsky" <boris.ostrovsky@oracle.com>
Subject: Re: [PATCH v3] cpuidle-haltpoll: vcpu hotplug support
Date: Mon, 2 Sep 2019 19:17:05 -0300 [thread overview]
Message-ID: <20190902221701.GA31730@amt.cnet> (raw)
In-Reply-To: <CAJZ5v0g1rjRsaC1R2xvtn4WtCaWtedFQk+oNUgB5sPAc6cU8rA@mail.gmail.com>
On Mon, Sep 02, 2019 at 10:34:07PM +0200, Rafael J. Wysocki wrote:
> On Mon, Sep 2, 2019 at 12:43 PM Joao Martins <joao.m.martins@oracle.com> wrote:
> >
> > When cpus != maxcpus cpuidle-haltpoll will fail to register all vcpus
> > past the online ones and thus fail to register the idle driver.
> > This is because cpuidle_add_sysfs() will return with -ENODEV as a
> > consequence from get_cpu_device() return no device for a non-existing
> > CPU.
> >
> > Instead switch to cpuidle_register_driver() and manually register each
> > of the present cpus through cpuhp_setup_state() callbacks and future
> > ones that get onlined or offlined. This mimmics similar logic that
> > intel_idle does.
> >
> > Fixes: fa86ee90eb11 ("add cpuidle-haltpoll driver")
> > Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
> > Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
> > ---
> > v3:
> > * register the teardown callback for correct handling of hotunplug
> > and error cases. In case cpuhp_setup_state calls fails (e.g. in one of
> > the cpus that it invoked the callback) it will then call the teardown of
> > the previously enabled devices; so no need to handle that manually in
> > haltpoll_uninit().
> > * use the cpuhp_setup_state() returned dyn allocated state when it
> > succeeds. And use that state in haltpoll_unint() to call
> > cpuhp_remove_state() instead of looping online cpus manually. This
> > is because cpuhp_remove_state() invokes the teardown/offline callback.
> > * fix subsystem name to 'cpuidle' instead of 'idle' in cpuhp_setup_state()
>
> Marcelo, is the R-by still applicable?
>
> Paolo, any comments?
>
> >
> > v2:
> > * move cpus_read_unlock() after unregistering all cpuidle_devices;
> > (Marcello Tosatti)
> > * redundant usage of cpuidle_unregister() when only
> > cpuidle_unregister_driver() suffices; (Marcelo Tosatti)
> > * cpuhp_setup_state() returns a state (> 0) for CPUHP_AP_ONLINE_DYN
> > ---
> > arch/x86/include/asm/cpuidle_haltpoll.h | 4 +-
> > arch/x86/kernel/kvm.c | 18 +++----
> > drivers/cpuidle/cpuidle-haltpoll.c | 68 +++++++++++++++++++++++--
> > include/linux/cpuidle_haltpoll.h | 4 +-
> > 4 files changed, 73 insertions(+), 21 deletions(-)
> >
> > diff --git a/arch/x86/include/asm/cpuidle_haltpoll.h b/arch/x86/include/asm/cpuidle_haltpoll.h
> > index ff8607d81526..c8b39c6716ff 100644
> > --- a/arch/x86/include/asm/cpuidle_haltpoll.h
> > +++ b/arch/x86/include/asm/cpuidle_haltpoll.h
> > @@ -2,7 +2,7 @@
> > #ifndef _ARCH_HALTPOLL_H
> > #define _ARCH_HALTPOLL_H
> >
> > -void arch_haltpoll_enable(void);
> > -void arch_haltpoll_disable(void);
> > +void arch_haltpoll_enable(unsigned int cpu);
> > +void arch_haltpoll_disable(unsigned int cpu);
> >
> > #endif
> > diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> > index 8d150e3732d9..a9b6c4e2446d 100644
> > --- a/arch/x86/kernel/kvm.c
> > +++ b/arch/x86/kernel/kvm.c
> > @@ -880,32 +880,26 @@ static void kvm_enable_host_haltpoll(void *i)
> > wrmsrl(MSR_KVM_POLL_CONTROL, 1);
> > }
> >
> > -void arch_haltpoll_enable(void)
> > +void arch_haltpoll_enable(unsigned int cpu)
> > {
> > if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) {
> > - printk(KERN_ERR "kvm: host does not support poll control\n");
> > - printk(KERN_ERR "kvm: host upgrade recommended\n");
> > + pr_err_once("kvm: host does not support poll control\n");
> > + pr_err_once("kvm: host upgrade recommended\n");
> > return;
> > }
> >
> > - preempt_disable();
> > /* Enable guest halt poll disables host halt poll */
> > - kvm_disable_host_haltpoll(NULL);
> > - smp_call_function(kvm_disable_host_haltpoll, NULL, 1);
> > - preempt_enable();
> > + smp_call_function_single(cpu, kvm_disable_host_haltpoll, NULL, 1);
> > }
> > EXPORT_SYMBOL_GPL(arch_haltpoll_enable);
> >
> > -void arch_haltpoll_disable(void)
> > +void arch_haltpoll_disable(unsigned int cpu)
> > {
> > if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL))
> > return;
> >
> > - preempt_disable();
> > /* Enable guest halt poll disables host halt poll */
> > - kvm_enable_host_haltpoll(NULL);
> > - smp_call_function(kvm_enable_host_haltpoll, NULL, 1);
> > - preempt_enable();
> > + smp_call_function_single(cpu, kvm_enable_host_haltpoll, NULL, 1);
> > }
> > EXPORT_SYMBOL_GPL(arch_haltpoll_disable);
> > #endif
> > diff --git a/drivers/cpuidle/cpuidle-haltpoll.c b/drivers/cpuidle/cpuidle-haltpoll.c
> > index 9ac093dcbb01..56d8ab814466 100644
> > --- a/drivers/cpuidle/cpuidle-haltpoll.c
> > +++ b/drivers/cpuidle/cpuidle-haltpoll.c
> > @@ -11,12 +11,16 @@
> > */
> >
> > #include <linux/init.h>
> > +#include <linux/cpu.h>
> > #include <linux/cpuidle.h>
> > #include <linux/module.h>
> > #include <linux/sched/idle.h>
> > #include <linux/kvm_para.h>
> > #include <linux/cpuidle_haltpoll.h>
> >
> > +static struct cpuidle_device __percpu *haltpoll_cpuidle_devices;
> > +static enum cpuhp_state haltpoll_hp_state;
> > +
> > static int default_enter_idle(struct cpuidle_device *dev,
> > struct cpuidle_driver *drv, int index)
> > {
> > @@ -46,6 +50,46 @@ static struct cpuidle_driver haltpoll_driver = {
> > .state_count = 2,
> > };
> >
> > +static int haltpoll_cpu_online(unsigned int cpu)
> > +{
> > + struct cpuidle_device *dev;
> > +
> > + dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
> > + if (!dev->registered) {
> > + dev->cpu = cpu;
> > + if (cpuidle_register_device(dev)) {
> > + pr_notice("cpuidle_register_device %d failed!\n", cpu);
> > + return -EIO;
> > + }
> > + arch_haltpoll_enable(cpu);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int haltpoll_cpu_offline(unsigned int cpu)
> > +{
> > + struct cpuidle_device *dev;
> > +
> > + dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
> > + if (dev->registered) {
> > + arch_haltpoll_disable(cpu);
> > + cpuidle_unregister_device(dev);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static void haltpoll_uninit(void)
> > +{
> > + if (haltpoll_hp_state)
> > + cpuhp_remove_state(haltpoll_hp_state);
> > + cpuidle_unregister_driver(&haltpoll_driver);
> > +
> > + free_percpu(haltpoll_cpuidle_devices);
> > + haltpoll_cpuidle_devices = NULL;
> > +}
> > +
> > static int __init haltpoll_init(void)
> > {
> > int ret;
> > @@ -56,17 +100,31 @@ static int __init haltpoll_init(void)
> > if (!kvm_para_available())
> > return 0;
> >
> > - ret = cpuidle_register(&haltpoll_driver, NULL);
> > - if (ret == 0)
> > - arch_haltpoll_enable();
> > + ret = cpuidle_register_driver(drv);
> > + if (ret < 0)
> > + return ret;
> > +
> > + haltpoll_cpuidle_devices = alloc_percpu(struct cpuidle_device);
> > + if (haltpoll_cpuidle_devices == NULL) {
> > + cpuidle_unregister_driver(drv);
> > + return -ENOMEM;
> > + }
> > +
> > + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpuidle/haltpoll:online",
> > + haltpoll_cpu_online, haltpoll_cpu_offline);
> > + if (ret < 0) {
> > + haltpoll_uninit();
> > + } else {
> > + haltpoll_hp_state = ret;
> > + ret = 0;
> > + }
> >
> > return ret;
> > }
> >
> > static void __exit haltpoll_exit(void)
> > {
> > - arch_haltpoll_disable();
> > - cpuidle_unregister(&haltpoll_driver);
> > + haltpoll_uninit();
> > }
> >
> > module_init(haltpoll_init);
> > diff --git a/include/linux/cpuidle_haltpoll.h b/include/linux/cpuidle_haltpoll.h
> > index fe5954c2409e..d50c1e0411a2 100644
> > --- a/include/linux/cpuidle_haltpoll.h
> > +++ b/include/linux/cpuidle_haltpoll.h
> > @@ -5,11 +5,11 @@
> > #ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL
> > #include <asm/cpuidle_haltpoll.h>
> > #else
> > -static inline void arch_haltpoll_enable(void)
> > +static inline void arch_haltpoll_enable(unsigned int cpu)
> > {
> > }
> >
> > -static inline void arch_haltpoll_disable(void)
> > +static inline void arch_haltpoll_disable(unsigned int cpu)
> > {
> > }
> > #endif
> > --
> > 2.17.1
> >
Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
next prev parent reply other threads:[~2019-09-02 22:18 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-09-02 10:40 [PATCH v3] cpuidle-haltpoll: vcpu hotplug support Joao Martins
2019-09-02 20:34 ` Rafael J. Wysocki
2019-09-02 22:17 ` Marcelo Tosatti [this message]
2019-09-03 7:38 ` Rafael J. Wysocki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190902221701.GA31730@amt.cnet \
--to=mtosatti@redhat.com \
--cc=boris.ostrovsky@oracle.com \
--cc=daniel.lezcano@linaro.org \
--cc=jmattson@google.com \
--cc=joao.m.martins@oracle.com \
--cc=joro@8bytes.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=rafael@kernel.org \
--cc=rjw@rjwysocki.net \
--cc=rkrcmar@redhat.com \
--cc=sean.j.christopherson@intel.com \
--cc=vkuznets@redhat.com \
--cc=wanpengli@tencent.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.