* [PATCH v3 3/3] fbdev: fbmem: avoid exporting fb_center_logo
From: Peter Rosin @ 2019-08-27 11:09 UTC (permalink / raw)
To: linux-kernel@vger.kernel.org
Cc: Peter Rosin, Bartlomiej Zolnierkiewicz, Jonathan Corbet,
dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org,
linux-doc@vger.kernel.org, Matthew Wilcox, Geert Uytterhoeven
In-Reply-To: <20190827110854.12574-1-peda@axentia.se>
The variable is only ever used from fbcon.c which is linked into the
same module. Therefore, the export is not needed.
Signed-off-by: Peter Rosin <peda@axentia.se>
---
drivers/video/fbdev/core/fbmem.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index c7ddcb72025b..d45e59ac351b 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -54,7 +54,6 @@ int num_registered_fb __read_mostly;
EXPORT_SYMBOL(num_registered_fb);
bool fb_center_logo __read_mostly;
-EXPORT_SYMBOL(fb_center_logo);
int fb_logo_count __read_mostly = -1;
--
2.11.0
^ permalink raw reply related
* Re: [PATCH v3 1/3] fbdev: fix numbering of fbcon options
From: Geert Uytterhoeven @ 2019-08-27 11:25 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel@vger.kernel.org, Bartlomiej Zolnierkiewicz,
Jonathan Corbet, dri-devel@lists.freedesktop.org,
linux-fbdev@vger.kernel.org, linux-doc@vger.kernel.org,
Matthew Wilcox
In-Reply-To: <20190827110854.12574-2-peda@axentia.se>
On Tue, Aug 27, 2019 at 1:09 PM Peter Rosin <peda@axentia.se> wrote:
> Three shall be the number thou shalt count, and the number of the
> counting shall be three. Four shalt thou not count...
>
> One! Two! Five!
>
> Fixes: efb985f6b265 ("[PATCH] fbcon: Console Rotation - Add framebuffer console documentation")
> Signed-off-by: Peter Rosin <peda@axentia.se>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v3 2/3] fbdev: fbmem: allow overriding the number of bootup logos
From: Geert Uytterhoeven @ 2019-08-27 11:25 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel@vger.kernel.org, Bartlomiej Zolnierkiewicz,
Jonathan Corbet, dri-devel@lists.freedesktop.org,
linux-fbdev@vger.kernel.org, linux-doc@vger.kernel.org,
Matthew Wilcox
In-Reply-To: <20190827110854.12574-3-peda@axentia.se>
On Tue, Aug 27, 2019 at 1:09 PM Peter Rosin <peda@axentia.se> wrote:
> Probably most useful if you want no logo at all, or if you only want one
> logo regardless of how many CPU cores you have.
>
> Signed-off-by: Peter Rosin <peda@axentia.se>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v3 3/3] fbdev: fbmem: avoid exporting fb_center_logo
From: Geert Uytterhoeven @ 2019-08-27 11:35 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel@vger.kernel.org, Bartlomiej Zolnierkiewicz,
Jonathan Corbet, dri-devel@lists.freedesktop.org,
linux-fbdev@vger.kernel.org, linux-doc@vger.kernel.org,
Matthew Wilcox
In-Reply-To: <20190827110854.12574-4-peda@axentia.se>
Hi Peter,
On Tue, Aug 27, 2019 at 1:09 PM Peter Rosin <peda@axentia.se> wrote:
> The variable is only ever used from fbcon.c which is linked into the
> same module. Therefore, the export is not needed.
>
> Signed-off-by: Peter Rosin <peda@axentia.se>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
But note that the same is true for fb_class, so perhaps it can be added
(or better, removed ;-)?
Once drivers/staging/olpc_dcon/olpc_dcon.c stops abusing registered_fb[]
and num_registered_fb, those can go, too.
Does anyone remembe why au1200fb calls fb_prepare_logo() and fb_show_logo()
itself?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 4.19 72/98] x86/CPU/AMD: Clear RDRAND CPUID bit on AMD family 15h/16h
From: Pavel Machek @ 2019-08-27 11:36 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-kernel, stable, Tom Lendacky, Borislav Petkov,
Andrew Cooper, Andrew Morton, Chen Yu, H. Peter Anvin,
Ingo Molnar, Jonathan Corbet, Josh Poimboeuf, Juergen Gross,
Kees Cook, linux-doc@vger.kernel.org, linux-pm@vger.kernel.org,
Nathan Chancellor, Paolo Bonzini, Rafael J. Wysocki,
Thomas Gleixner, x86@kernel.org
In-Reply-To: <20190827072722.020603090@linuxfoundation.org>
[-- Attachment #1: Type: text/plain, Size: 11406 bytes --]
On Tue 2019-08-27 09:50:51, Greg Kroah-Hartman wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> commit c49a0a80137c7ca7d6ced4c812c9e07a949f6f24 upstream.
>
> There have been reports of RDRAND issues after resuming from suspend on
> some AMD family 15h and family 16h systems. This issue stems from a BIOS
> not performing the proper steps during resume to ensure RDRAND continues
> to function properly.
Yes. And instead of reinitializing the RDRAND on resume, this patch
breaks support even for people with properly functioning BIOSes...
Also note that this is nowhere near minimum fix, and over 100 line
limit.
Best regards,
Pavel
>
> RDRAND support is indicated by CPUID Fn00000001_ECX[30]. This bit can be
> reset by clearing MSR C001_1004[62]. Any software that checks for RDRAND
> support using CPUID, including the kernel, will believe that RDRAND is
> not supported.
>
> Update the CPU initialization to clear the RDRAND CPUID bit for any family
> 15h and 16h processor that supports RDRAND. If it is known that the family
> 15h or family 16h system does not have an RDRAND resume issue or that the
> system will not be placed in suspend, the "rdrand=force" kernel parameter
> can be used to stop the clearing of the RDRAND CPUID bit.
>
> Additionally, update the suspend and resume path to save and restore the
> MSR C001_1004 value to ensure that the RDRAND CPUID setting remains in
> place after resuming from suspend.
>
> Note, that clearing the RDRAND CPUID bit does not prevent a processor
> that normally supports the RDRAND instruction from executing it. So any
> code that determined the support based on family and model won't #UD.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> Signed-off-by: Borislav Petkov <bp@suse.de>
> Cc: Andrew Cooper <andrew.cooper3@citrix.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Chen Yu <yu.c.chen@intel.com>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Josh Poimboeuf <jpoimboe@redhat.com>
> Cc: Juergen Gross <jgross@suse.com>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: "linux-doc@vger.kernel.org" <linux-doc@vger.kernel.org>
> Cc: "linux-pm@vger.kernel.org" <linux-pm@vger.kernel.org>
> Cc: Nathan Chancellor <natechancellor@gmail.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Pavel Machek <pavel@ucw.cz>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> Cc: <stable@vger.kernel.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: "x86@kernel.org" <x86@kernel.org>
> Link: https://lkml.kernel.org/r/7543af91666f491547bd86cebb1e17c66824ab9f.1566229943.git.thomas.lendacky@amd.com
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> ---
> Documentation/admin-guide/kernel-parameters.txt | 7 +
> arch/x86/include/asm/msr-index.h | 1
> arch/x86/kernel/cpu/amd.c | 66 ++++++++++++++++++
> arch/x86/power/cpu.c | 86 ++++++++++++++++++++----
> 4 files changed, 147 insertions(+), 13 deletions(-)
>
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -3948,6 +3948,13 @@
> Run specified binary instead of /init from the ramdisk,
> used for early userspace startup. See initrd.
>
> + rdrand= [X86]
> + force - Override the decision by the kernel to hide the
> + advertisement of RDRAND support (this affects
> + certain AMD processors because of buggy BIOS
> + support, specifically around the suspend/resume
> + path).
> +
> rdt= [HW,X86,RDT]
> Turn on/off individual RDT features. List is:
> cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
> --- a/arch/x86/include/asm/msr-index.h
> +++ b/arch/x86/include/asm/msr-index.h
> @@ -334,6 +334,7 @@
> #define MSR_AMD64_PATCH_LEVEL 0x0000008b
> #define MSR_AMD64_TSC_RATIO 0xc0000104
> #define MSR_AMD64_NB_CFG 0xc001001f
> +#define MSR_AMD64_CPUID_FN_1 0xc0011004
> #define MSR_AMD64_PATCH_LOADER 0xc0010020
> #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
> #define MSR_AMD64_OSVW_STATUS 0xc0010141
> --- a/arch/x86/kernel/cpu/amd.c
> +++ b/arch/x86/kernel/cpu/amd.c
> @@ -799,6 +799,64 @@ static void init_amd_ln(struct cpuinfo_x
> msr_set_bit(MSR_AMD64_DE_CFG, 31);
> }
>
> +static bool rdrand_force;
> +
> +static int __init rdrand_cmdline(char *str)
> +{
> + if (!str)
> + return -EINVAL;
> +
> + if (!strcmp(str, "force"))
> + rdrand_force = true;
> + else
> + return -EINVAL;
> +
> + return 0;
> +}
> +early_param("rdrand", rdrand_cmdline);
> +
> +static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
> +{
> + /*
> + * Saving of the MSR used to hide the RDRAND support during
> + * suspend/resume is done by arch/x86/power/cpu.c, which is
> + * dependent on CONFIG_PM_SLEEP.
> + */
> + if (!IS_ENABLED(CONFIG_PM_SLEEP))
> + return;
> +
> + /*
> + * The nordrand option can clear X86_FEATURE_RDRAND, so check for
> + * RDRAND support using the CPUID function directly.
> + */
> + if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force)
> + return;
> +
> + msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62);
> +
> + /*
> + * Verify that the CPUID change has occurred in case the kernel is
> + * running virtualized and the hypervisor doesn't support the MSR.
> + */
> + if (cpuid_ecx(1) & BIT(30)) {
> + pr_info_once("BIOS may not properly restore RDRAND after suspend, but hypervisor does not support hiding RDRAND via CPUID.\n");
> + return;
> + }
> +
> + clear_cpu_cap(c, X86_FEATURE_RDRAND);
> + pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding RDRAND via CPUID. Use rdrand=force to reenable.\n");
> +}
> +
> +static void init_amd_jg(struct cpuinfo_x86 *c)
> +{
> + /*
> + * Some BIOS implementations do not restore proper RDRAND support
> + * across suspend and resume. Check on whether to hide the RDRAND
> + * instruction support via CPUID.
> + */
> + clear_rdrand_cpuid_bit(c);
> +}
> +
> static void init_amd_bd(struct cpuinfo_x86 *c)
> {
> u64 value;
> @@ -813,6 +871,13 @@ static void init_amd_bd(struct cpuinfo_x
> wrmsrl_safe(MSR_F15H_IC_CFG, value);
> }
> }
> +
> + /*
> + * Some BIOS implementations do not restore proper RDRAND support
> + * across suspend and resume. Check on whether to hide the RDRAND
> + * instruction support via CPUID.
> + */
> + clear_rdrand_cpuid_bit(c);
> }
>
> static void init_amd_zn(struct cpuinfo_x86 *c)
> @@ -855,6 +920,7 @@ static void init_amd(struct cpuinfo_x86
> case 0x10: init_amd_gh(c); break;
> case 0x12: init_amd_ln(c); break;
> case 0x15: init_amd_bd(c); break;
> + case 0x16: init_amd_jg(c); break;
> case 0x17: init_amd_zn(c); break;
> }
>
> --- a/arch/x86/power/cpu.c
> +++ b/arch/x86/power/cpu.c
> @@ -13,6 +13,7 @@
> #include <linux/smp.h>
> #include <linux/perf_event.h>
> #include <linux/tboot.h>
> +#include <linux/dmi.h>
>
> #include <asm/pgtable.h>
> #include <asm/proto.h>
> @@ -24,7 +25,7 @@
> #include <asm/debugreg.h>
> #include <asm/cpu.h>
> #include <asm/mmu_context.h>
> -#include <linux/dmi.h>
> +#include <asm/cpu_device_id.h>
>
> #ifdef CONFIG_X86_32
> __visible unsigned long saved_context_ebx;
> @@ -398,15 +399,14 @@ static int __init bsp_pm_check_init(void
>
> core_initcall(bsp_pm_check_init);
>
> -static int msr_init_context(const u32 *msr_id, const int total_num)
> +static int msr_build_context(const u32 *msr_id, const int num)
> {
> - int i = 0;
> + struct saved_msrs *saved_msrs = &saved_context.saved_msrs;
> struct saved_msr *msr_array;
> + int total_num;
> + int i, j;
>
> - if (saved_context.saved_msrs.array || saved_context.saved_msrs.num > 0) {
> - pr_err("x86/pm: MSR quirk already applied, please check your DMI match table.\n");
> - return -EINVAL;
> - }
> + total_num = saved_msrs->num + num;
>
> msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
> if (!msr_array) {
> @@ -414,19 +414,30 @@ static int msr_init_context(const u32 *m
> return -ENOMEM;
> }
>
> - for (i = 0; i < total_num; i++) {
> - msr_array[i].info.msr_no = msr_id[i];
> + if (saved_msrs->array) {
> + /*
> + * Multiple callbacks can invoke this function, so copy any
> + * MSR save requests from previous invocations.
> + */
> + memcpy(msr_array, saved_msrs->array,
> + sizeof(struct saved_msr) * saved_msrs->num);
> +
> + kfree(saved_msrs->array);
> + }
> +
> + for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
> + msr_array[i].info.msr_no = msr_id[j];
> msr_array[i].valid = false;
> msr_array[i].info.reg.q = 0;
> }
> - saved_context.saved_msrs.num = total_num;
> - saved_context.saved_msrs.array = msr_array;
> + saved_msrs->num = total_num;
> + saved_msrs->array = msr_array;
>
> return 0;
> }
>
> /*
> - * The following section is a quirk framework for problematic BIOSen:
> + * The following sections are a quirk framework for problematic BIOSen:
> * Sometimes MSRs are modified by the BIOSen after suspended to
> * RAM, this might cause unexpected behavior after wakeup.
> * Thus we save/restore these specified MSRs across suspend/resume
> @@ -441,7 +452,7 @@ static int msr_initialize_bdw(const stru
> u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
>
> pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
> - return msr_init_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
> + return msr_build_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
> }
>
> static const struct dmi_system_id msr_save_dmi_table[] = {
> @@ -456,9 +467,58 @@ static const struct dmi_system_id msr_sa
> {}
> };
>
> +static int msr_save_cpuid_features(const struct x86_cpu_id *c)
> +{
> + u32 cpuid_msr_id[] = {
> + MSR_AMD64_CPUID_FN_1,
> + };
> +
> + pr_info("x86/pm: family %#hx cpu detected, MSR saving is needed during suspending.\n",
> + c->family);
> +
> + return msr_build_context(cpuid_msr_id, ARRAY_SIZE(cpuid_msr_id));
> +}
> +
> +static const struct x86_cpu_id msr_save_cpu_table[] = {
> + {
> + .vendor = X86_VENDOR_AMD,
> + .family = 0x15,
> + .model = X86_MODEL_ANY,
> + .feature = X86_FEATURE_ANY,
> + .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
> + },
> + {
> + .vendor = X86_VENDOR_AMD,
> + .family = 0x16,
> + .model = X86_MODEL_ANY,
> + .feature = X86_FEATURE_ANY,
> + .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
> + },
> + {}
> +};
> +
> +typedef int (*pm_cpu_match_t)(const struct x86_cpu_id *);
> +static int pm_cpu_check(const struct x86_cpu_id *c)
> +{
> + const struct x86_cpu_id *m;
> + int ret = 0;
> +
> + m = x86_match_cpu(msr_save_cpu_table);
> + if (m) {
> + pm_cpu_match_t fn;
> +
> + fn = (pm_cpu_match_t)m->driver_data;
> + ret = fn(m);
> + }
> +
> + return ret;
> +}
> +
> static int pm_check_save_msr(void)
> {
> dmi_check_system(msr_save_dmi_table);
> + pm_cpu_check(msr_save_cpu_table);
> +
> return 0;
> }
>
>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [PATCH V3 0/3] KVM/Hyper-V: Add Hyper-V direct tlb flush support
From: Tianyu Lan @ 2019-08-27 12:17 UTC (permalink / raw)
To: Vitaly Kuznetsov
Cc: Tianyu Lan, kvm, linux-doc, linux-hyperv,
linux-kernel@vger kernel org, Paolo Bonzini, Radim Krcmar, corbet,
KY Srinivasan, Haiyang Zhang, Stephen Hemminger, Sasha Levin,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
the arch/x86 maintainers, michael.h.kelley
In-Reply-To: <87ftlnm7o8.fsf@vitty.brq.redhat.com>
On Tue, Aug 27, 2019 at 2:41 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>
> lantianyu1986@gmail.com writes:
>
> > From: Tianyu Lan <Tianyu.Lan@microsoft.com>
> >
> > This patchset is to add Hyper-V direct tlb support in KVM. Hyper-V
> > in L0 can delegate L1 hypervisor to handle tlb flush request from
> > L2 guest when direct tlb flush is enabled in L1.
> >
> > Patch 2 introduces new cap KVM_CAP_HYPERV_DIRECT_TLBFLUSH to enable
> > feature from user space. User space should enable this feature only
> > when Hyper-V hypervisor capability is exposed to guest and KVM profile
> > is hided. There is a parameter conflict between KVM and Hyper-V hypercall.
> > We hope L2 guest doesn't use KVM hypercall when the feature is
> > enabled. Detail please see comment of new API
> > "KVM_CAP_HYPERV_DIRECT_TLBFLUSH"
>
> I was thinking about this for awhile and I think I have a better
> proposal. Instead of adding this new capability let's enable direct TLB
> flush when KVM guest enables Hyper-V Hypercall page (writes to
> HV_X64_MSR_HYPERCALL) - this guarantees that the guest doesn't need KVM
> hypercalls as we can't handle both KVM-style and Hyper-V-style
> hypercalls simultaneously and kvm_emulate_hypercall() does:
>
> if (kvm_hv_hypercall_enabled(vcpu->kvm))
> return kvm_hv_hypercall(vcpu);
>
> What do you think?
>
> (and instead of adding the capability we can add kvm.ko module parameter
> to enable direct tlb flush unconditionally, like
> 'hv_direct_tlbflush=-1/0/1' with '-1' being the default (autoselect
> based on Hyper-V hypercall enablement, '0' - permanently disabled, '1' -
> permanenetly enabled)).
>
Hi Vitaly::
Actually, I had such idea before. But user space should check
whether hv tlb flush
is exposed to VM before enabling direct tlb flush. If no, user space
should not direct
tlb flush for guest since Hyper-V will do more check for each
hypercall from nested
VM with enabling the feauter..
--
Best regards
Tianyu Lan
^ permalink raw reply
* [PATCH] Documentation: add link to stm32mp157 docs
From: Gerald BAEZA @ 2019-08-27 12:19 UTC (permalink / raw)
To: corbet@lwn.net, mcoquelin.stm32@gmail.com, Alexandre TORGUE,
linux-doc@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: Gerald BAEZA
Link to the online stm32mp157 documentation added
in the overview.
Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
---
Documentation/arm/stm32/stm32mp157-overview.rst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/arm/stm32/stm32mp157-overview.rst b/Documentation/arm/stm32/stm32mp157-overview.rst
index f62fdc8..8d5a476 100644
--- a/Documentation/arm/stm32/stm32mp157-overview.rst
+++ b/Documentation/arm/stm32/stm32mp157-overview.rst
@@ -14,6 +14,12 @@ It features:
- Standard connectivity, widely inherited from the STM32 MCU family
- Comprehensive security support
+Resources
+---------
+
+Datasheet and reference manual are publicly available on ST website:
+.. _STM32MP157: https://www.st.com/en/microcontrollers-microprocessors/stm32mp157.html
+
:Authors:
- Ludovic Barre <ludovic.barre@st.com>
--
2.7.4
^ permalink raw reply related
* Re: [PATCH V3 0/3] KVM/Hyper-V: Add Hyper-V direct tlb flush support
From: Tianyu Lan @ 2019-08-27 12:33 UTC (permalink / raw)
To: Vitaly Kuznetsov
Cc: Tianyu Lan, kvm, linux-doc, linux-hyperv,
linux-kernel@vger kernel org, Paolo Bonzini, Radim Krcmar, corbet,
KY Srinivasan, Haiyang Zhang, Stephen Hemminger, Sasha Levin,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
the arch/x86 maintainers, michael.h.kelley
In-Reply-To: <CAOLK0pzXPG9tBnQoKGTSNHMwXXrEQ4zZH1uWn2F2mQ2ddVcoFA@mail.gmail.com>
On Tue, Aug 27, 2019 at 8:17 PM Tianyu Lan <lantianyu1986@gmail.com> wrote:
>
> On Tue, Aug 27, 2019 at 2:41 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> >
> > lantianyu1986@gmail.com writes:
> >
> > > From: Tianyu Lan <Tianyu.Lan@microsoft.com>
> > >
> > > This patchset is to add Hyper-V direct tlb support in KVM. Hyper-V
> > > in L0 can delegate L1 hypervisor to handle tlb flush request from
> > > L2 guest when direct tlb flush is enabled in L1.
> > >
> > > Patch 2 introduces new cap KVM_CAP_HYPERV_DIRECT_TLBFLUSH to enable
> > > feature from user space. User space should enable this feature only
> > > when Hyper-V hypervisor capability is exposed to guest and KVM profile
> > > is hided. There is a parameter conflict between KVM and Hyper-V hypercall.
> > > We hope L2 guest doesn't use KVM hypercall when the feature is
> > > enabled. Detail please see comment of new API
> > > "KVM_CAP_HYPERV_DIRECT_TLBFLUSH"
> >
> > I was thinking about this for awhile and I think I have a better
> > proposal. Instead of adding this new capability let's enable direct TLB
> > flush when KVM guest enables Hyper-V Hypercall page (writes to
> > HV_X64_MSR_HYPERCALL) - this guarantees that the guest doesn't need KVM
> > hypercalls as we can't handle both KVM-style and Hyper-V-style
> > hypercalls simultaneously and kvm_emulate_hypercall() does:
> >
> > if (kvm_hv_hypercall_enabled(vcpu->kvm))
> > return kvm_hv_hypercall(vcpu);
> >
> > What do you think?
> >
> > (and instead of adding the capability we can add kvm.ko module parameter
> > to enable direct tlb flush unconditionally, like
> > 'hv_direct_tlbflush=-1/0/1' with '-1' being the default (autoselect
> > based on Hyper-V hypercall enablement, '0' - permanently disabled, '1' -
> > permanenetly enabled)).
> >
>
> Hi Vitaly::
> Actually, I had such idea before. But user space should check
> whether hv tlb flush
> is exposed to VM before enabling direct tlb flush. If no, user space
> should not direct
> tlb flush for guest since Hyper-V will do more check for each
> hypercall from nested
> VM with enabling the feauter..
>
Fix the line break.Sorry for noise.
Actually, I had such idea before. But user space should check
whether hv tlb flush is exposed to VM before enabling direct tlb
flush. If no, user space should not direct tlb flush for guest since
Hyper-V will do more check for each hypercall from nested VM
with enabling the feauter..
---
Best regards
Tianyu Lan
^ permalink raw reply
* Re: [PATCH V3 0/3] KVM/Hyper-V: Add Hyper-V direct tlb flush support
From: Vitaly Kuznetsov @ 2019-08-27 12:38 UTC (permalink / raw)
To: Tianyu Lan
Cc: Tianyu Lan, kvm, linux-doc, linux-hyperv,
linux-kernel@vger kernel org, Paolo Bonzini, Radim Krcmar, corbet,
KY Srinivasan, Haiyang Zhang, Stephen Hemminger, Sasha Levin,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
the arch/x86 maintainers, michael.h.kelley
In-Reply-To: <CAOLK0pzXPG9tBnQoKGTSNHMwXXrEQ4zZH1uWn2F2mQ2ddVcoFA@mail.gmail.com>
Tianyu Lan <lantianyu1986@gmail.com> writes:
> On Tue, Aug 27, 2019 at 2:41 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>>
>> lantianyu1986@gmail.com writes:
>>
>> > From: Tianyu Lan <Tianyu.Lan@microsoft.com>
>> >
>> > This patchset is to add Hyper-V direct tlb support in KVM. Hyper-V
>> > in L0 can delegate L1 hypervisor to handle tlb flush request from
>> > L2 guest when direct tlb flush is enabled in L1.
>> >
>> > Patch 2 introduces new cap KVM_CAP_HYPERV_DIRECT_TLBFLUSH to enable
>> > feature from user space. User space should enable this feature only
>> > when Hyper-V hypervisor capability is exposed to guest and KVM profile
>> > is hided. There is a parameter conflict between KVM and Hyper-V hypercall.
>> > We hope L2 guest doesn't use KVM hypercall when the feature is
>> > enabled. Detail please see comment of new API
>> > "KVM_CAP_HYPERV_DIRECT_TLBFLUSH"
>>
>> I was thinking about this for awhile and I think I have a better
>> proposal. Instead of adding this new capability let's enable direct TLB
>> flush when KVM guest enables Hyper-V Hypercall page (writes to
>> HV_X64_MSR_HYPERCALL) - this guarantees that the guest doesn't need KVM
>> hypercalls as we can't handle both KVM-style and Hyper-V-style
>> hypercalls simultaneously and kvm_emulate_hypercall() does:
>>
>> if (kvm_hv_hypercall_enabled(vcpu->kvm))
>> return kvm_hv_hypercall(vcpu);
>>
>> What do you think?
>>
>> (and instead of adding the capability we can add kvm.ko module parameter
>> to enable direct tlb flush unconditionally, like
>> 'hv_direct_tlbflush=-1/0/1' with '-1' being the default (autoselect
>> based on Hyper-V hypercall enablement, '0' - permanently disabled, '1' -
>> permanenetly enabled)).
>>
>
> Hi Vitaly::
> Actually, I had such idea before. But user space should check
> whether hv tlb flush
> is exposed to VM before enabling direct tlb flush. If no, user space
> should not direct
> tlb flush for guest since Hyper-V will do more check for each
> hypercall from nested
> VM with enabling the feauter..
If TLB Flush enlightenment is not exposed to the VM at all there's no
difference if we enable direct TLB flush in eVMCS or not: the guest
won't be using 'TLB Flush' hypercall and will do TLB flushing with
IPIs. And, in case the guest enables Hyper-V hypercall page, it is
definitelly not going to use KVM hypercalls so we can't break these.
--
Vitaly
^ permalink raw reply
* Re: [PATCH v3 10/10] arm64: Retrieve stolen time as paravirtualized guest
From: Zenghui Yu @ 2019-08-27 12:43 UTC (permalink / raw)
To: Steven Price, Marc Zyngier, Will Deacon, linux-arm-kernel, kvmarm
Cc: kvm, linux-doc, Catalin Marinas, Russell King, linux-kernel,
Paolo Bonzini
In-Reply-To: <29cd1304-6b4d-05ef-3c08-6b4ba769c8fa@arm.com>
On 2019/8/23 22:22, Steven Price wrote:
> On 23/08/2019 12:45, Zenghui Yu wrote:
>> Hi Steven,
>>
>> On 2019/8/21 23:36, Steven Price wrote:
>>> Enable paravirtualization features when running under a hypervisor
>>> supporting the PV_TIME_ST hypercall.
>>>
>>> For each (v)CPU, we ask the hypervisor for the location of a shared
>>> page which the hypervisor will use to report stolen time to us. We set
>>> pv_time_ops to the stolen time function which simply reads the stolen
>>> value from the shared page for a VCPU. We guarantee single-copy
>>> atomicity using READ_ONCE which means we can also read the stolen
>>> time for another VCPU than the currently running one while it is
>>> potentially being updated by the hypervisor.
>>>
>>> Signed-off-by: Steven Price <steven.price@arm.com>
>>> ---
>>> arch/arm64/include/asm/paravirt.h | 9 +-
>>> arch/arm64/kernel/paravirt.c | 148 ++++++++++++++++++++++++++++++
>>> arch/arm64/kernel/time.c | 3 +
>>> include/linux/cpuhotplug.h | 1 +
>>> 4 files changed, 160 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm64/include/asm/paravirt.h
>>> b/arch/arm64/include/asm/paravirt.h
>>> index 799d9dd6f7cc..125c26c42902 100644
>>> --- a/arch/arm64/include/asm/paravirt.h
>>> +++ b/arch/arm64/include/asm/paravirt.h
>>> @@ -21,6 +21,13 @@ static inline u64 paravirt_steal_clock(int cpu)
>>> {
>>> return pv_ops.time.steal_clock(cpu);
>>> }
>>> -#endif
>>> +
>>> +int __init kvm_guest_init(void);
>>> +
>>> +#else
>>> +
>>> +#define kvm_guest_init()
>>> +
>>> +#endif // CONFIG_PARAVIRT
>>> #endif
>>> diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c
>>> index 4cfed91fe256..ea8dbbbd3293 100644
>>> --- a/arch/arm64/kernel/paravirt.c
>>> +++ b/arch/arm64/kernel/paravirt.c
>>> @@ -6,13 +6,161 @@
>>> * Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>>> */
>>> +#define pr_fmt(fmt) "kvmarm-pv: " fmt
>>> +
>>> +#include <linux/arm-smccc.h>
>>> +#include <linux/cpuhotplug.h>
>>> #include <linux/export.h>
>>> +#include <linux/io.h>
>>> #include <linux/jump_label.h>
>>> +#include <linux/printk.h>
>>> +#include <linux/psci.h>
>>> +#include <linux/reboot.h>
>>> +#include <linux/slab.h>
>>> #include <linux/types.h>
>>> +
>>> #include <asm/paravirt.h>
>>> +#include <asm/pvclock-abi.h>
>>> +#include <asm/smp_plat.h>
>>> struct static_key paravirt_steal_enabled;
>>> struct static_key paravirt_steal_rq_enabled;
>>> struct paravirt_patch_template pv_ops;
>>> EXPORT_SYMBOL_GPL(pv_ops);
>>> +
>>> +struct kvmarm_stolen_time_region {
>>> + struct pvclock_vcpu_stolen_time *kaddr;
>>> +};
>>> +
>>> +static DEFINE_PER_CPU(struct kvmarm_stolen_time_region,
>>> stolen_time_region);
>>> +
>>> +static bool steal_acc = true;
>>> +static int __init parse_no_stealacc(char *arg)
>>> +{
>>> + steal_acc = false;
>>> + return 0;
>>> +}
>>> +
>>> +early_param("no-steal-acc", parse_no_stealacc);
>>> +
>>> +/* return stolen time in ns by asking the hypervisor */
>>> +static u64 kvm_steal_clock(int cpu)
>>> +{
>>> + struct kvmarm_stolen_time_region *reg;
>>> +
>>> + reg = per_cpu_ptr(&stolen_time_region, cpu);
>>> + if (!reg->kaddr) {
>>> + pr_warn_once("stolen time enabled but not configured for cpu
>>> %d\n",
>>> + cpu);
>>> + return 0;
>>> + }
>>> +
>>> + return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time));
>>> +}
>>> +
>>> +static int disable_stolen_time_current_cpu(void)
>>> +{
>>> + struct kvmarm_stolen_time_region *reg;
>>> +
>>> + reg = this_cpu_ptr(&stolen_time_region);
>>> + if (!reg->kaddr)
>>> + return 0;
>>> +
>>> + memunmap(reg->kaddr);
>>> + memset(reg, 0, sizeof(*reg));
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int stolen_time_dying_cpu(unsigned int cpu)
>>> +{
>>> + return disable_stolen_time_current_cpu();
>>> +}
>>> +
>>> +static int init_stolen_time_cpu(unsigned int cpu)
>>> +{
>>> + struct kvmarm_stolen_time_region *reg;
>>> + struct arm_smccc_res res;
>>> +
>>> + reg = this_cpu_ptr(&stolen_time_region);
>>> +
>>> + arm_smccc_1_1_invoke(ARM_SMCCC_HV_PV_TIME_ST, &res);
>>> +
>>> + if ((long)res.a0 < 0)
>>> + return -EINVAL;
>>> +
>>> + reg->kaddr = memremap(res.a0,
>>> + sizeof(struct pvclock_vcpu_stolen_time),
>>> + MEMREMAP_WB);
>>
>> cpuhp callbacks can be invoked in atomic context (see:
>> secondary_start_kernel ->
>> notify_cpu_starting ->
>> invoke callbacks),
>> but memremap might sleep...
>>
>> Try to run a DEBUG_ATOMIC_SLEEP enabled PV guest, I guess we will be
>> greeted by the Sleep-in-Atomic-Context BUG. We need an alternative
>> here?
>
> Actually I had run DEBUG_ATOMIC_SLEEP and not seen any issue. But I
> think that's because of the way I've configured the region in my kvmtool
> changes. I'm hitting the path where the memory region is in the linear
> map of the kernel and so no actual remapping is needed and hence
> memremap doesn't sleep (the shared structure is in a reserved region of
> RAM).
>
> But even changing the memory layout of the guest so the call goes into
> ioremap_page_range() (which contains a might_sleep()) I'm not seeing any
> problems.
Emm, I hit this SAC BUG when testing your V1 with the kvmtool changes
you've provided, but forgot to report it at that time. I go back to V1
and get the following call trace:
[ 0.120113] BUG: sleeping function called from invalid context at
mm/slab.h:501
[ 0.120118] in_atomic(): 1, irqs_disabled(): 128, pid: 0, name: swapper/1
[ 0.120122] no locks held by swapper/1/0.
[ 0.120126] irq event stamp: 0
[ 0.120135] hardirqs last enabled at (0): [<0000000000000000>] 0x0
[ 0.120145] hardirqs last disabled at (0): [<ffff200010113b40>]
copy_process+0x870/0x2878
[ 0.120152] softirqs last enabled at (0): [<ffff200010113b40>]
copy_process+0x870/0x2878
[ 0.120157] softirqs last disabled at (0): [<0000000000000000>] 0x0
[ 0.120164] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 5.3.0-rc6+ #2
[ 0.120168] Hardware name: linux,dummy-virt (DT)
[ 0.120173] Call trace:
[ 0.120179] dump_backtrace+0x0/0x250
[ 0.120184] show_stack+0x24/0x30
[ 0.120192] dump_stack+0x120/0x174
[ 0.120198] ___might_sleep+0x1b0/0x280
[ 0.120203] __might_sleep+0x80/0xf0
[ 0.120209] kmem_cache_alloc_node_trace+0x30c/0x3c8
[ 0.120216] __get_vm_area_node+0x9c/0x208
[ 0.120221] get_vm_area_caller+0x58/0x68
[ 0.120227] __ioremap_caller+0x78/0x120
[ 0.120233] ioremap_cache+0xf0/0x1a8
[ 0.120240] memremap+0x154/0x3b8
[ 0.120245] init_stolen_time_cpu+0x94/0x150
[ 0.120251] cpuhp_invoke_callback+0x12c/0x12f8
[ 0.120257] notify_cpu_starting+0xa0/0xc0
[ 0.120263] secondary_start_kernel+0x1d4/0x328
But things may have changed because we're talking about V3 now...
I will dig it a bit deeper.
> Am I missing something? I have to admit I don't entirely follow the
> early start up - perhaps it's a simple as DEBUG_ATOMIC_SLEEP doesn't
> work this early in boot?
I think it should work.
Thanks,
zenghui
^ permalink raw reply
* Re: [PATCH V3 0/3] KVM/Hyper-V: Add Hyper-V direct tlb flush support
From: Tianyu Lan @ 2019-08-27 13:07 UTC (permalink / raw)
To: Vitaly Kuznetsov
Cc: Tianyu Lan, kvm, linux-doc, linux-hyperv,
linux-kernel@vger kernel org, Paolo Bonzini, Radim Krcmar, corbet,
KY Srinivasan, Haiyang Zhang, Stephen Hemminger, Sasha Levin,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
the arch/x86 maintainers, michael.h.kelley
In-Reply-To: <87v9uilr5x.fsf@vitty.brq.redhat.com>
On Tue, Aug 27, 2019 at 8:38 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>
> Tianyu Lan <lantianyu1986@gmail.com> writes:
>
> > On Tue, Aug 27, 2019 at 2:41 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> >>
> >> lantianyu1986@gmail.com writes:
> >>
> >> > From: Tianyu Lan <Tianyu.Lan@microsoft.com>
> >> >
> >> > This patchset is to add Hyper-V direct tlb support in KVM. Hyper-V
> >> > in L0 can delegate L1 hypervisor to handle tlb flush request from
> >> > L2 guest when direct tlb flush is enabled in L1.
> >> >
> >> > Patch 2 introduces new cap KVM_CAP_HYPERV_DIRECT_TLBFLUSH to enable
> >> > feature from user space. User space should enable this feature only
> >> > when Hyper-V hypervisor capability is exposed to guest and KVM profile
> >> > is hided. There is a parameter conflict between KVM and Hyper-V hypercall.
> >> > We hope L2 guest doesn't use KVM hypercall when the feature is
> >> > enabled. Detail please see comment of new API
> >> > "KVM_CAP_HYPERV_DIRECT_TLBFLUSH"
> >>
> >> I was thinking about this for awhile and I think I have a better
> >> proposal. Instead of adding this new capability let's enable direct TLB
> >> flush when KVM guest enables Hyper-V Hypercall page (writes to
> >> HV_X64_MSR_HYPERCALL) - this guarantees that the guest doesn't need KVM
> >> hypercalls as we can't handle both KVM-style and Hyper-V-style
> >> hypercalls simultaneously and kvm_emulate_hypercall() does:
> >>
> >> if (kvm_hv_hypercall_enabled(vcpu->kvm))
> >> return kvm_hv_hypercall(vcpu);
> >>
> >> What do you think?
> >>
> >> (and instead of adding the capability we can add kvm.ko module parameter
> >> to enable direct tlb flush unconditionally, like
> >> 'hv_direct_tlbflush=-1/0/1' with '-1' being the default (autoselect
> >> based on Hyper-V hypercall enablement, '0' - permanently disabled, '1' -
> >> permanenetly enabled)).
> >>
> >
> > Hi Vitaly::
> > Actually, I had such idea before. But user space should check
> > whether hv tlb flush
> > is exposed to VM before enabling direct tlb flush. If no, user space
> > should not direct
> > tlb flush for guest since Hyper-V will do more check for each
> > hypercall from nested
> > VM with enabling the feauter..
>
> If TLB Flush enlightenment is not exposed to the VM at all there's no
> difference if we enable direct TLB flush in eVMCS or not: the guest
> won't be using 'TLB Flush' hypercall and will do TLB flushing with
> IPIs. And, in case the guest enables Hyper-V hypercall page, it is
> definitelly not going to use KVM hypercalls so we can't break these.
>
Yes, this won't tigger KVM/Hyper-V hypercall conflict. My point is
that if tlb flush enlightenment is not enabled, enabling direct tlb
flush will not accelate anything and Hyper-V still will check each
hypercalls from nested VM in order to intercpt tlb flush hypercall
But guest won't use tlb flush hypercall in this case. The check
of each hypercall in Hyper-V is redundant. We may avoid the
overhead via checking status of tlb flush enlightenment and just
enable direct tlb flush when it's enabled.
---
Best regards
Tianyu Lan
^ permalink raw reply
* Re: [PATCH V3 0/3] KVM/Hyper-V: Add Hyper-V direct tlb flush support
From: Vitaly Kuznetsov @ 2019-08-27 13:29 UTC (permalink / raw)
To: Tianyu Lan
Cc: Tianyu Lan, kvm, linux-doc, linux-hyperv,
linux-kernel@vger kernel org, Paolo Bonzini, Radim Krcmar, corbet,
KY Srinivasan, Haiyang Zhang, Stephen Hemminger, Sasha Levin,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
the arch/x86 maintainers, michael.h.kelley
In-Reply-To: <CAOLK0py2rvYkLPP9uQ6Q7y31Btu4XOsWr3Vsk6GtUDWvg5uUOg@mail.gmail.com>
Tianyu Lan <lantianyu1986@gmail.com> writes:
> On Tue, Aug 27, 2019 at 8:38 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>>
>> Tianyu Lan <lantianyu1986@gmail.com> writes:
>>
>> > On Tue, Aug 27, 2019 at 2:41 PM Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>> >>
>> >> lantianyu1986@gmail.com writes:
>> >>
>> >> > From: Tianyu Lan <Tianyu.Lan@microsoft.com>
>> >> >
>> >> > This patchset is to add Hyper-V direct tlb support in KVM. Hyper-V
>> >> > in L0 can delegate L1 hypervisor to handle tlb flush request from
>> >> > L2 guest when direct tlb flush is enabled in L1.
>> >> >
>> >> > Patch 2 introduces new cap KVM_CAP_HYPERV_DIRECT_TLBFLUSH to enable
>> >> > feature from user space. User space should enable this feature only
>> >> > when Hyper-V hypervisor capability is exposed to guest and KVM profile
>> >> > is hided. There is a parameter conflict between KVM and Hyper-V hypercall.
>> >> > We hope L2 guest doesn't use KVM hypercall when the feature is
>> >> > enabled. Detail please see comment of new API
>> >> > "KVM_CAP_HYPERV_DIRECT_TLBFLUSH"
>> >>
>> >> I was thinking about this for awhile and I think I have a better
>> >> proposal. Instead of adding this new capability let's enable direct TLB
>> >> flush when KVM guest enables Hyper-V Hypercall page (writes to
>> >> HV_X64_MSR_HYPERCALL) - this guarantees that the guest doesn't need KVM
>> >> hypercalls as we can't handle both KVM-style and Hyper-V-style
>> >> hypercalls simultaneously and kvm_emulate_hypercall() does:
>> >>
>> >> if (kvm_hv_hypercall_enabled(vcpu->kvm))
>> >> return kvm_hv_hypercall(vcpu);
>> >>
>> >> What do you think?
>> >>
>> >> (and instead of adding the capability we can add kvm.ko module parameter
>> >> to enable direct tlb flush unconditionally, like
>> >> 'hv_direct_tlbflush=-1/0/1' with '-1' being the default (autoselect
>> >> based on Hyper-V hypercall enablement, '0' - permanently disabled, '1' -
>> >> permanenetly enabled)).
>> >>
>> >
>> > Hi Vitaly::
>> > Actually, I had such idea before. But user space should check
>> > whether hv tlb flush
>> > is exposed to VM before enabling direct tlb flush. If no, user space
>> > should not direct
>> > tlb flush for guest since Hyper-V will do more check for each
>> > hypercall from nested
>> > VM with enabling the feauter..
>>
>> If TLB Flush enlightenment is not exposed to the VM at all there's no
>> difference if we enable direct TLB flush in eVMCS or not: the guest
>> won't be using 'TLB Flush' hypercall and will do TLB flushing with
>> IPIs. And, in case the guest enables Hyper-V hypercall page, it is
>> definitelly not going to use KVM hypercalls so we can't break these.
>>
>
> Yes, this won't tigger KVM/Hyper-V hypercall conflict. My point is
> that if tlb flush enlightenment is not enabled, enabling direct tlb
> flush will not accelate anything and Hyper-V still will check each
> hypercalls from nested VM in order to intercpt tlb flush hypercall
> But guest won't use tlb flush hypercall in this case. The check
> of each hypercall in Hyper-V is redundant. We may avoid the
> overhead via checking status of tlb flush enlightenment and just
> enable direct tlb flush when it's enabled.
Oh, I see. Yes, this optimization is possible and I'm not against it,
however I doubt it will make a significant difference because no matter
what upon VMCALL we first drop into L0 which can either inject this in
L1 or, in case of direct TLB flush, execute it by itself. Checking if
the hypercall is a TLB flush hypercall is just a register read, it
should be very cheap.
--
Vitaly
^ permalink raw reply
* Re: [PATCH 4.19 72/98] x86/CPU/AMD: Clear RDRAND CPUID bit on AMD family 15h/16h
From: Thomas Gleixner @ 2019-08-27 13:30 UTC (permalink / raw)
To: Pavel Machek
Cc: Greg Kroah-Hartman, linux-kernel, stable, Tom Lendacky,
Borislav Petkov, Andrew Cooper, Andrew Morton, Chen Yu,
H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Josh Poimboeuf,
Juergen Gross, Kees Cook, linux-doc@vger.kernel.org,
linux-pm@vger.kernel.org, Nathan Chancellor, Paolo Bonzini,
Rafael J. Wysocki, x86@kernel.org
In-Reply-To: <20190827113604.GB18218@amd>
On Tue, 27 Aug 2019, Pavel Machek wrote:
> On Tue 2019-08-27 09:50:51, Greg Kroah-Hartman wrote:
> > From: Tom Lendacky <thomas.lendacky@amd.com>
> >
> > commit c49a0a80137c7ca7d6ced4c812c9e07a949f6f24 upstream.
> >
> > There have been reports of RDRAND issues after resuming from suspend on
> > some AMD family 15h and family 16h systems. This issue stems from a BIOS
> > not performing the proper steps during resume to ensure RDRAND continues
> > to function properly.
>
> Yes. And instead of reinitializing the RDRAND on resume, this patch
> breaks support even for people with properly functioning BIOSes...
There is no way to reinitialize RDRAND from the kernel otherwise we would
have exactly done that. If you know how to do that please tell.
Also disabling it for every BIOS is the only way which can be done because
there is no way to know whether the BIOS is fixed or not at cold boot
time. And it has to be known there because applications cache the
availablity and continue using it after resume and because the valid bit is
set they wont notice.
There is a know to turn it back on for those who are sure that it works,
but the default has to be: OFF simply because we cannot endanger everyone
out there with a broken BIOS just to please you.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH] Documentation: add link to stm32mp157 docs
From: Jonathan Corbet @ 2019-08-27 13:48 UTC (permalink / raw)
To: Gerald BAEZA
Cc: mcoquelin.stm32@gmail.com, Alexandre TORGUE,
linux-doc@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <1566908347-92201-1-git-send-email-gerald.baeza@st.com>
On Tue, 27 Aug 2019 12:19:32 +0000
Gerald BAEZA <gerald.baeza@st.com> wrote:
> Link to the online stm32mp157 documentation added
> in the overview.
>
> Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
> ---
> Documentation/arm/stm32/stm32mp157-overview.rst | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/Documentation/arm/stm32/stm32mp157-overview.rst b/Documentation/arm/stm32/stm32mp157-overview.rst
> index f62fdc8..8d5a476 100644
> --- a/Documentation/arm/stm32/stm32mp157-overview.rst
> +++ b/Documentation/arm/stm32/stm32mp157-overview.rst
> @@ -14,6 +14,12 @@ It features:
> - Standard connectivity, widely inherited from the STM32 MCU family
> - Comprehensive security support
>
> +Resources
> +---------
> +
> +Datasheet and reference manual are publicly available on ST website:
> +.. _STM32MP157: https://www.st.com/en/microcontrollers-microprocessors/stm32mp157.html
> +
Adding the URL is a fine idea. But you don't need the extra syntax to
create a link if you're not going to actually make a link out of it. So
I'd take the ".. _STM32MP157:" part out and life will be good.
Thanks,
jon
^ permalink raw reply
* [PATCH v3 2/5] dt-bindings: perf: stm32: ddrperfm support
From: Gerald BAEZA @ 2019-08-27 15:08 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robh+dt@kernel.org,
mcoquelin.stm32@gmail.com, Alexandre TORGUE, corbet@lwn.net,
linux@armlinux.org.uk, olof@lixom.net, arnd@arndb.de,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gerald BAEZA
In-Reply-To: <1566918464-23927-1-git-send-email-gerald.baeza@st.com>
The DDRPERFM is the DDR Performance Monitor embedded in STM32MP1 SOC.
This documentation indicates how to enable stm32-ddr-pmu driver on
DDRPERFM peripheral, via the device tree.
Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
---
Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt
diff --git a/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt
new file mode 100644
index 0000000..87ab12e
--- /dev/null
+++ b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt
@@ -0,0 +1,16 @@
+* STM32 DDR Performance Monitor (DDRPERFM)
+
+Required properties:
+- compatible: must be "st,stm32-ddr-pmu".
+- reg: physical address and length of the registers set.
+- clocks: phandle and specifier for DDRPERFM input clock
+- resets: phandle and specifier for DDRPERFM reset
+
+Example:
+ ddrperfm: perf@5a007000 {
+ compatible = "st,stm32-ddr-pmu";
+ reg = <0x5a007000 0x400>;
+ clocks = <&rcc DDRPERFM>;
+ resets = <&rcc DDRPERFM_R>;
+ };
+
--
2.7.4
^ permalink raw reply related
* [PATCH v3 0/5] stm32-ddr-pmu driver creation
From: Gerald BAEZA @ 2019-08-27 15:08 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robh+dt@kernel.org,
mcoquelin.stm32@gmail.com, Alexandre TORGUE, corbet@lwn.net,
linux@armlinux.org.uk, olof@lixom.net, arnd@arndb.de,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gerald BAEZA
The DDRPERFM is the DDR Performance Monitor embedded in STM32MP1 SOC.
This series adds support for the DDRPERFM via a new stm32-ddr-pmu driver,
registered into the perf framework.
This driver is inspired from arch/arm/mm/cache-l2x0-pmu.c
---
Changes from v1:
- add 'resets' description (bindings) and using (driver). Thanks Rob.
- rebase on 5.2-rc1 (that includes the ddrperfm clock control patch).
Changes from v2:
- rebase on 5.3-rc6 that has to be completed with
'perf tools: fix alignment trap in perf stat': mandatory.
'Documentation: add link to stm32mp157 docs': referenced from this series.
- take into account all remarks from Mark Rutland: thanks for your time!
https://lkml.org/lkml/2019/6/26/388
- fix for event type filtering in stm32_ddr_pmu_event_init()
Gerald Baeza (5):
Documentation: perf: stm32: ddrperfm support
dt-bindings: perf: stm32: ddrperfm support
perf: stm32: ddrperfm driver creation
ARM: configs: enable STM32_DDR_PMU
ARM: dts: stm32: add ddrperfm on stm32mp157c
.../devicetree/bindings/perf/stm32-ddr-pmu.txt | 16 +
Documentation/perf/stm32-ddr-pmu.txt | 37 ++
arch/arm/boot/dts/stm32mp157c.dtsi | 8 +
arch/arm/configs/multi_v7_defconfig | 1 +
drivers/perf/Kconfig | 6 +
drivers/perf/Makefile | 1 +
drivers/perf/stm32_ddr_pmu.c | 426 +++++++++++++++++++++
7 files changed, 495 insertions(+)
create mode 100644 Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt
create mode 100644 Documentation/perf/stm32-ddr-pmu.txt
create mode 100644 drivers/perf/stm32_ddr_pmu.c
--
2.7.4
^ permalink raw reply
* [PATCH v3 1/5] Documentation: perf: stm32: ddrperfm support
From: Gerald BAEZA @ 2019-08-27 15:08 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robh+dt@kernel.org,
mcoquelin.stm32@gmail.com, Alexandre TORGUE, corbet@lwn.net,
linux@armlinux.org.uk, olof@lixom.net, arnd@arndb.de,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gerald BAEZA
In-Reply-To: <1566918464-23927-1-git-send-email-gerald.baeza@st.com>
The DDRPERFM is the DDR Performance Monitor embedded in STM32MP1 SOC.
This documentation introduces the DDRPERFM, the stm32-ddr-pmu driver
supporting it and how to use it with the perf tool.
Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
---
Documentation/perf/stm32-ddr-pmu.txt | 37 ++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 Documentation/perf/stm32-ddr-pmu.txt
diff --git a/Documentation/perf/stm32-ddr-pmu.txt b/Documentation/perf/stm32-ddr-pmu.txt
new file mode 100644
index 0000000..557bf47
--- /dev/null
+++ b/Documentation/perf/stm32-ddr-pmu.txt
@@ -0,0 +1,37 @@
+STM32 DDR Performance Monitor (DDRPERFM)
+========================================
+
+The DDRPERFM is the DDR Performance Monitor embedded in STM32MP1 SOC.
+See Documentation/arm/stm32/stm32mp157-overview.rst to get access to
+STM32MP157 reference manual RM0436 where DDRPERFM is described.
+
+
+The five following counters are supported by stm32-ddr-pmu driver:
+ cnt0: read operations counters (read_cnt)
+ cnt1: write operations counters (write_cnt)
+ cnt2: active state counters (activate_cnt)
+ cnt3: idle state counters (idle_cnt)
+ tcnt: time count, present for all sets (time_cnt)
+
+The stm32-ddr-pmu driver relies on the perf PMU framework to expose the
+counters via sysfs:
+ $ ls /sys/bus/event_source/devices/ddrperfm/events
+ activate_cnt idle_cnt read_cnt time_cnt write_cnt
+
+
+The perf PMU framework is usually invoked via the 'perf stat' tool.
+
+The DDRPERFM is a system monitor that cannot isolate the traffic coming from a
+given thread or CPU, that is why stm32-ddr-pmu driver rejects any 'perf stat'
+call that does not request a system-wide collection: the '-a, --all-cpus'
+option is mandatory!
+
+Example:
+ $ perf stat -e ddrperfm/read_cnt/,ddrperfm/time_cnt/ -a sleep 20
+ Performance counter stats for 'system wide':
+
+ 342541560 ddrperfm/read_cnt/
+ 10660011400 ddrperfm/time_cnt/
+
+ 20.021068551 seconds time elapsed
+
--
2.7.4
^ permalink raw reply related
* [PATCH v3 5/5] ARM: dts: stm32: add ddrperfm on stm32mp157c
From: Gerald BAEZA @ 2019-08-27 15:08 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robh+dt@kernel.org,
mcoquelin.stm32@gmail.com, Alexandre TORGUE, corbet@lwn.net,
linux@armlinux.org.uk, olof@lixom.net, arnd@arndb.de,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gerald BAEZA
In-Reply-To: <1566918464-23927-1-git-send-email-gerald.baeza@st.com>
The DDRPERFM is the DDR Performance Monitor embedded
in STM32MP1 SOC.
Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
---
arch/arm/boot/dts/stm32mp157c.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index 0c4e6eb..6ea6933 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -1378,6 +1378,14 @@
};
};
+ ddrperfm: perf@5a007000 {
+ compatible = "st,stm32-ddr-pmu";
+ reg = <0x5a007000 0x400>;
+ clocks = <&rcc DDRPERFM>;
+ resets = <&rcc DDRPERFM_R>;
+ status = "okay";
+ };
+
usart1: serial@5c000000 {
compatible = "st,stm32h7-uart";
reg = <0x5c000000 0x400>;
--
2.7.4
^ permalink raw reply related
* [PATCH v3 3/5] perf: stm32: ddrperfm driver creation
From: Gerald BAEZA @ 2019-08-27 15:08 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robh+dt@kernel.org,
mcoquelin.stm32@gmail.com, Alexandre TORGUE, corbet@lwn.net,
linux@armlinux.org.uk, olof@lixom.net, arnd@arndb.de,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gerald BAEZA
In-Reply-To: <1566918464-23927-1-git-send-email-gerald.baeza@st.com>
The DDRPERFM is the DDR Performance Monitor embedded in STM32MP1 SOC.
This perf drivers supports the read, write, activate, idle and total
time counters, described in the reference manual RM0436 that is
accessible from Documentation/arm/stm32/stm32mp157-overview.rst
Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
---
drivers/perf/Kconfig | 6 +
drivers/perf/Makefile | 1 +
drivers/perf/stm32_ddr_pmu.c | 426 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 433 insertions(+)
create mode 100644 drivers/perf/stm32_ddr_pmu.c
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 09ae8a9..a3d917e 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -114,6 +114,12 @@ config THUNDERX2_PMU
The SoC has PMU support in its L3 cache controller (L3C) and
in the DDR4 Memory Controller (DMC).
+config STM32_DDR_PMU
+ tristate "STM32 DDR PMU"
+ depends on MACH_STM32MP157
+ help
+ Support for STM32 DDR performance monitor (DDRPERFM).
+
config XGENE_PMU
depends on ARCH_XGENE
bool "APM X-Gene SoC PMU"
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index 2ebb4de..fd3368c 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o
obj-$(CONFIG_HISI_PMU) += hisilicon/
obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o
obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o
+obj-$(CONFIG_STM32_DDR_PMU) += stm32_ddr_pmu.o
obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o
diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c
new file mode 100644
index 0000000..d0480e0
--- /dev/null
+++ b/drivers/perf/stm32_ddr_pmu.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is the STM32 DDR performance monitor (DDRPERFM) driver
+ *
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ * Author: Gerald Baeza <gerald.baeza@st.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/perf_event.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/*
+ * The PMU is able to freeze all counters and generate an interrupt when there
+ * is a counter overflow. But, relying on this means that we lose all the
+ * events that occur between the freeze and the interrupt handler execution.
+ * So we use a polling mechanism to avoid this lose of information.
+ * The fastest counter can overflow in ~8s @533MHz (that is the maximum DDR
+ * frequency supported on STM32MP157), so we poll in 4s intervals to ensure
+ * we don't reach this limit.
+ */
+#define POLL_MS 4000
+
+#define DDRPERFM_CTL 0x000
+#define DDRPERFM_CFG 0x004
+#define DDRPERFM_STATUS 0x008
+#define DDRPERFM_CCR 0x00C
+#define DDRPERFM_IER 0x010
+#define DDRPERFM_ISR 0x014
+#define DDRPERFM_ICR 0x018
+#define DDRPERFM_TCNT 0x020
+#define DDRPERFM_CNT(X) (0x030 + 8 * (X))
+#define DDRPERFM_HWCFG 0x3F0
+#define DDRPERFM_VER 0x3F4
+#define DDRPERFM_ID 0x3F8
+#define DDRPERFM_SID 0x3FC
+
+#define CTL_START 0x00000001
+#define CTL_STOP 0x00000002
+#define CCR_CLEAR_ALL 0x8000000F
+#define SID_MAGIC_ID 0xA3C5DD01
+
+enum {
+ READ_CNT,
+ WRITE_CNT,
+ ACTIVATE_CNT,
+ IDLE_CNT,
+ TIME_CNT,
+ PMU_NR_COUNTERS
+};
+
+struct stm32_ddr_pmu {
+ struct pmu pmu;
+ void __iomem *membase;
+ struct clk *clk;
+ struct hrtimer hrtimer;
+ cpumask_t pmu_cpu;
+ ktime_t poll_period;
+ struct perf_event *events[PMU_NR_COUNTERS];
+ u64 events_cnt[PMU_NR_COUNTERS];
+};
+
+static inline struct stm32_ddr_pmu *pmu_to_stm32_ddr_pmu(struct pmu *p)
+{
+ return container_of(p, struct stm32_ddr_pmu, pmu);
+}
+
+static inline struct stm32_ddr_pmu *hrtimer_to_stm32_ddr_pmu(struct hrtimer *h)
+{
+ return container_of(h, struct stm32_ddr_pmu, hrtimer);
+}
+
+static void stm32_ddr_pmu_event_configure(struct perf_event *event)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ unsigned long config_base = event->hw.config_base;
+ u32 val;
+
+ writel_relaxed(CTL_STOP, stm32_ddr_pmu->membase + DDRPERFM_CTL);
+
+ if (config_base < TIME_CNT) {
+ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_CFG);
+ val |= (1 << config_base);
+ writel_relaxed(val, stm32_ddr_pmu->membase + DDRPERFM_CFG);
+ }
+}
+
+static void stm32_ddr_pmu_event_read(struct perf_event *event)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ unsigned long config_base = event->hw.config_base;
+ struct hw_perf_event *hw = &event->hw;
+ u64 prev_count, new_count, mask;
+ u32 val, offset, bit;
+
+ writel_relaxed(CTL_STOP, stm32_ddr_pmu->membase + DDRPERFM_CTL);
+
+ if (config_base == TIME_CNT) {
+ offset = DDRPERFM_TCNT;
+ bit = 1 << 31;
+ } else {
+ offset = DDRPERFM_CNT(config_base);
+ bit = 1 << config_base;
+ }
+ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_STATUS);
+ if (val & bit)
+ pr_warn("STM32 DDR PMU hardware counter overflow\n");
+ val = readl_relaxed(stm32_ddr_pmu->membase + offset);
+ writel_relaxed(bit, stm32_ddr_pmu->membase + DDRPERFM_CCR);
+ writel_relaxed(CTL_START, stm32_ddr_pmu->membase + DDRPERFM_CTL);
+
+ do {
+ prev_count = local64_read(&hw->prev_count);
+ new_count = prev_count + val;
+ } while (local64_xchg(&hw->prev_count, new_count) != prev_count);
+
+ mask = GENMASK_ULL(31, 0);
+ local64_add(val & mask, &event->count);
+
+ if (new_count < prev_count)
+ pr_warn("STM32 DDR PMU software counter rollover\n");
+}
+
+static void stm32_ddr_pmu_event_start(struct perf_event *event, int flags)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+
+ if (WARN_ON_ONCE(!(hw->state & PERF_HES_STOPPED)))
+ return;
+
+ if (flags & PERF_EF_RELOAD)
+ WARN_ON_ONCE(!(hw->state & PERF_HES_UPTODATE));
+
+ stm32_ddr_pmu_event_configure(event);
+
+ /* Clear all counters to synchronize them, then start */
+ writel_relaxed(CCR_CLEAR_ALL, stm32_ddr_pmu->membase + DDRPERFM_CCR);
+ writel_relaxed(CTL_START, stm32_ddr_pmu->membase + DDRPERFM_CTL);
+ local64_set(&hw->prev_count, 0);
+ hw->state = 0;
+}
+
+static void stm32_ddr_pmu_event_stop(struct perf_event *event, int flags)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ unsigned long config_base = event->hw.config_base;
+ struct hw_perf_event *hw = &event->hw;
+ u32 val, bit;
+
+ if (WARN_ON_ONCE(hw->state & PERF_HES_STOPPED))
+ return;
+
+ writel_relaxed(CTL_STOP, stm32_ddr_pmu->membase + DDRPERFM_CTL);
+ if (config_base == TIME_CNT)
+ bit = 1 << 31;
+ else
+ bit = 1 << config_base;
+ writel_relaxed(bit, stm32_ddr_pmu->membase + DDRPERFM_CCR);
+ if (config_base < TIME_CNT) {
+ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_CFG);
+ val &= ~bit;
+ writel_relaxed(val, stm32_ddr_pmu->membase + DDRPERFM_CFG);
+ }
+
+ hw->state |= PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_UPDATE) {
+ stm32_ddr_pmu_event_read(event);
+ hw->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int stm32_ddr_pmu_event_add(struct perf_event *event, int flags)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ unsigned long config_base = event->hw.config_base;
+ struct hw_perf_event *hw = &event->hw;
+
+ stm32_ddr_pmu->events_cnt[config_base] = 0;
+ stm32_ddr_pmu->events[config_base] = event;
+
+ clk_enable(stm32_ddr_pmu->clk);
+ /*
+ * Pin the timer, so that the overflows are handled by the chosen
+ * event->cpu (this is the same one as presented in "cpumask"
+ * attribute).
+ */
+ hrtimer_start(&stm32_ddr_pmu->hrtimer, stm32_ddr_pmu->poll_period,
+ HRTIMER_MODE_REL_PINNED);
+
+ stm32_ddr_pmu_event_configure(event);
+
+ hw->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+ if (flags & PERF_EF_START)
+ stm32_ddr_pmu_event_start(event, 0);
+
+ return 0;
+}
+
+static void stm32_ddr_pmu_event_del(struct perf_event *event, int flags)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ unsigned long config_base = event->hw.config_base;
+ bool stop = true;
+ int i;
+
+ stm32_ddr_pmu_event_stop(event, PERF_EF_UPDATE);
+
+ stm32_ddr_pmu->events_cnt[config_base] += local64_read(&event->count);
+ stm32_ddr_pmu->events[config_base] = NULL;
+
+ for (i = 0; i < PMU_NR_COUNTERS; i++)
+ if (stm32_ddr_pmu->events[i])
+ stop = false;
+ if (stop)
+ hrtimer_cancel(&stm32_ddr_pmu->hrtimer);
+
+ clk_disable(stm32_ddr_pmu->clk);
+}
+
+static int stm32_ddr_pmu_event_init(struct perf_event *event)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ if (is_sampling_event(event))
+ return -EINVAL;
+
+ if (event->attach_state & PERF_ATTACH_TASK)
+ return -EINVAL;
+
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ hw->config_base = event->attr.config;
+ event->cpu = cpumask_first(&stm32_ddr_pmu->pmu_cpu);
+
+ return 0;
+}
+
+static enum hrtimer_restart stm32_ddr_pmu_poll(struct hrtimer *hrtimer)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = hrtimer_to_stm32_ddr_pmu(hrtimer);
+ int i;
+
+ for (i = 0; i < PMU_NR_COUNTERS; i++)
+ if (stm32_ddr_pmu->events[i])
+ stm32_ddr_pmu_event_read(stm32_ddr_pmu->events[i]);
+
+ hrtimer_forward_now(hrtimer, stm32_ddr_pmu->poll_period);
+
+ return HRTIMER_RESTART;
+}
+
+static ssize_t stm32_ddr_pmu_sysfs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct dev_ext_attribute *eattr;
+
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
+
+ return sprintf(buf, "config=0x%lx\n", (unsigned long)eattr->var);
+}
+
+#define STM32_DDR_PMU_ATTR(_name, _func, _config) \
+ (&((struct dev_ext_attribute[]) { \
+ { __ATTR(_name, 0444, _func, NULL), (void *)_config } \
+ })[0].attr.attr)
+
+#define STM32_DDR_PMU_EVENT_ATTR(_name, _config) \
+ STM32_DDR_PMU_ATTR(_name, stm32_ddr_pmu_sysfs_show, \
+ (unsigned long)_config)
+
+static struct attribute *stm32_ddr_pmu_event_attrs[] = {
+ STM32_DDR_PMU_EVENT_ATTR(read_cnt, READ_CNT),
+ STM32_DDR_PMU_EVENT_ATTR(write_cnt, WRITE_CNT),
+ STM32_DDR_PMU_EVENT_ATTR(activate_cnt, ACTIVATE_CNT),
+ STM32_DDR_PMU_EVENT_ATTR(idle_cnt, IDLE_CNT),
+ STM32_DDR_PMU_EVENT_ATTR(time_cnt, TIME_CNT),
+ NULL
+};
+
+static struct attribute_group stm32_ddr_pmu_event_attrs_group = {
+ .name = "events",
+ .attrs = stm32_ddr_pmu_event_attrs,
+};
+
+static const struct attribute_group *stm32_ddr_pmu_attr_groups[] = {
+ &stm32_ddr_pmu_event_attrs_group,
+ NULL,
+};
+
+static int stm32_ddr_pmu_device_probe(struct platform_device *pdev)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu;
+ struct reset_control *rst;
+ struct resource *res;
+ int i, ret;
+ u32 val;
+
+ stm32_ddr_pmu = devm_kzalloc(&pdev->dev, sizeof(struct stm32_ddr_pmu),
+ GFP_KERNEL);
+ if (!stm32_ddr_pmu)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, stm32_ddr_pmu);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ stm32_ddr_pmu->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(stm32_ddr_pmu->membase)) {
+ pr_warn("Unable to get STM32 DDR PMU membase\n");
+ return PTR_ERR(stm32_ddr_pmu->membase);
+ }
+
+ stm32_ddr_pmu->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(stm32_ddr_pmu->clk)) {
+ pr_warn("Unable to get STM32 DDR PMU clock\n");
+ return PTR_ERR(stm32_ddr_pmu->clk);
+ }
+
+ ret = clk_prepare_enable(stm32_ddr_pmu->clk);
+ if (ret) {
+ pr_warn("Unable to prepare STM32 DDR PMU clock\n");
+ return ret;
+ }
+
+ stm32_ddr_pmu->poll_period = ms_to_ktime(POLL_MS);
+ hrtimer_init(&stm32_ddr_pmu->hrtimer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ stm32_ddr_pmu->hrtimer.function = stm32_ddr_pmu_poll;
+
+ /*
+ * The PMU is assigned to the cpu0 and there is no need to manage cpu
+ * hot plug migration because cpu0 is always the first/last active cpu
+ * during low power transitions.
+ */
+ cpumask_set_cpu(0, &stm32_ddr_pmu->pmu_cpu);
+
+ for (i = 0; i < PMU_NR_COUNTERS; i++) {
+ stm32_ddr_pmu->events[i] = NULL;
+ stm32_ddr_pmu->events_cnt[i] = 0;
+ }
+
+ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_SID);
+ if (val != SID_MAGIC_ID)
+ return -EINVAL;
+
+ stm32_ddr_pmu->pmu = (struct pmu) {
+ .task_ctx_nr = perf_invalid_context,
+ .start = stm32_ddr_pmu_event_start,
+ .stop = stm32_ddr_pmu_event_stop,
+ .add = stm32_ddr_pmu_event_add,
+ .del = stm32_ddr_pmu_event_del,
+ .event_init = stm32_ddr_pmu_event_init,
+ .attr_groups = stm32_ddr_pmu_attr_groups,
+ };
+ ret = perf_pmu_register(&stm32_ddr_pmu->pmu, "stm32_ddr_pmu", -1);
+ if (ret) {
+ pr_warn("Unable to register STM32 DDR PMU\n");
+ return ret;
+ }
+
+ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (!IS_ERR(rst)) {
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+ }
+
+ pr_info("stm32-ddr-pmu: probed (DDRPERFM ID=0x%08x VER=0x%08x)\n",
+ readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_ID),
+ readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_VER));
+
+ clk_disable(stm32_ddr_pmu->clk);
+
+ return 0;
+}
+
+static int stm32_ddr_pmu_device_remove(struct platform_device *pdev)
+{
+ struct stm32_ddr_pmu *stm32_ddr_pmu = platform_get_drvdata(pdev);
+
+ perf_pmu_unregister(&stm32_ddr_pmu->pmu);
+
+ return 0;
+}
+
+static const struct of_device_id stm32_ddr_pmu_of_match[] = {
+ { .compatible = "st,stm32-ddr-pmu" },
+ { },
+};
+
+static struct platform_driver stm32_ddr_pmu_driver = {
+ .driver = {
+ .name = "stm32-ddr-pmu",
+ .of_match_table = of_match_ptr(stm32_ddr_pmu_of_match),
+ },
+ .probe = stm32_ddr_pmu_device_probe,
+ .remove = stm32_ddr_pmu_device_remove,
+};
+
+module_platform_driver(stm32_ddr_pmu_driver);
+
+MODULE_DESCRIPTION("Perf driver for STM32 DDR performance monitor");
+MODULE_AUTHOR("Gerald Baeza <gerald.baeza@st.com>");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH v3 4/5] ARM: configs: enable STM32_DDR_PMU
From: Gerald BAEZA @ 2019-08-27 15:08 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robh+dt@kernel.org,
mcoquelin.stm32@gmail.com, Alexandre TORGUE, corbet@lwn.net,
linux@armlinux.org.uk, olof@lixom.net, arnd@arndb.de,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gerald BAEZA
In-Reply-To: <1566918464-23927-1-git-send-email-gerald.baeza@st.com>
STM32_DDR_PMU enables the perf driver that
controls the DDR Performance Monitor (DDRPERFM)
Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
---
arch/arm/configs/multi_v7_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 6a40bc2..8fa4690 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -1011,6 +1011,7 @@ CONFIG_PHY_DM816X_USB=m
CONFIG_OMAP_USB2=y
CONFIG_TI_PIPE3=y
CONFIG_TWL4030_USB=m
+CONFIG_STM32_DDR_PMU=m
CONFIG_MESON_MX_EFUSE=m
CONFIG_ROCKCHIP_EFUSE=m
CONFIG_NVMEM_IMX_OCOTP=y
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] Documentation: add link to stm32mp157 docs
From: Alexandre Torgue @ 2019-08-27 15:23 UTC (permalink / raw)
To: Jonathan Corbet, Gerald BAEZA
Cc: mcoquelin.stm32@gmail.com, linux-doc@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20190827074825.64a28e88@lwn.net>
Hi Jonathan,
On 8/27/19 3:48 PM, Jonathan Corbet wrote:
> On Tue, 27 Aug 2019 12:19:32 +0000
> Gerald BAEZA <gerald.baeza@st.com> wrote:
>
>> Link to the online stm32mp157 documentation added
>> in the overview.
>>
>> Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
>> ---
>> Documentation/arm/stm32/stm32mp157-overview.rst | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/Documentation/arm/stm32/stm32mp157-overview.rst b/Documentation/arm/stm32/stm32mp157-overview.rst
>> index f62fdc8..8d5a476 100644
>> --- a/Documentation/arm/stm32/stm32mp157-overview.rst
>> +++ b/Documentation/arm/stm32/stm32mp157-overview.rst
>> @@ -14,6 +14,12 @@ It features:
>> - Standard connectivity, widely inherited from the STM32 MCU family
>> - Comprehensive security support
>>
>> +Resources
>> +---------
>> +
>> +Datasheet and reference manual are publicly available on ST website:
>> +.. _STM32MP157: https://www.st.com/en/microcontrollers-microprocessors/stm32mp157.html
>> +
>
> Adding the URL is a fine idea. But you don't need the extra syntax to
> create a link if you're not going to actually make a link out of it. So
> I'd take the ".. _STM32MP157:" part out and life will be good.
>
We also did it for older stm32 product. Idea was to not have the "full"
address but just a shortcut of the link when html file is read. It maybe
makes no sens ? (if yes we will have to update older stm32 overview :))
thanks
Alex
> Thanks,
>
> jon
>
^ permalink raw reply
* Re: [PATCH] Documentation: Rename rcu_node_context_switch() to rcu_note_context_switch()
From: Paul E. McKenney @ 2019-08-27 16:02 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Joel Fernandes, Scott Wood, linux-kernel, Thomas Gleixner,
Peter Zijlstra, Juri Lelli, Clark Williams, Josh Triplett,
Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, Jonathan Corbet,
rcu, linux-doc
In-Reply-To: <20190827093603.x2dist7q5e2z36c5@linutronix.de>
On Tue, Aug 27, 2019 at 11:36:03AM +0200, Sebastian Andrzej Siewior wrote:
> While Paul was explaning some RCU magic I noticed a typo in
> rcu_note_context_switch().
> Replace rcu_node_context_switch() with rcu_note_context_switch().
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Good eyes, queued for v5.5, thank you!
Sounds like I should explain RCU magic more often, then. ;-)
Thanx, Paul
> ---
> .../RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html | 2 +-
> Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg | 2 +-
> Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg | 2 +-
> 3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html b/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html
> index c64f8d26609fb..54db02b74f636 100644
> --- a/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html
> +++ b/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html
> @@ -481,7 +481,7 @@ section that the grace period must wait on.
> </table>
>
> <p>If the CPU does a context switch, a quiescent state will be
> -noted by <tt>rcu_node_context_switch()</tt> on the left.
> +noted by <tt>rcu_note_context_switch()</tt> on the left.
> On the other hand, if the CPU takes a scheduler-clock interrupt
> while executing in usermode, a quiescent state will be noted by
> <tt>rcu_sched_clock_irq()</tt> on the right.
> diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg
> index 2bcd742d6e491..069f6f8371c20 100644
> --- a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg
> +++ b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg
> @@ -3880,7 +3880,7 @@
> font-style="normal"
> y="-4418.6582"
> x="3745.7725"
> - xml:space="preserve">rcu_node_context_switch()</text>
> + xml:space="preserve">rcu_note_context_switch()</text>
> </g>
> <g
> transform="translate(1881.1886,54048.57)"
> diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg
> index 779c9ac31a527..7d6c5f7e505c6 100644
> --- a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg
> +++ b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg
> @@ -753,7 +753,7 @@
> font-style="normal"
> y="-4418.6582"
> x="3745.7725"
> - xml:space="preserve">rcu_node_context_switch()</text>
> + xml:space="preserve">rcu_note_context_switch()</text>
> </g>
> <g
> transform="translate(3131.2648,-585.6713)"
> --
> 2.23.0
>
^ permalink raw reply
* [PATCH 0/5] kfree_rcu() additions for -rcu
From: Joel Fernandes (Google) @ 2019-08-27 19:01 UTC (permalink / raw)
To: linux-kernel
Cc: Joel Fernandes (Google), byungchul.park, Josh Triplett,
Lai Jiangshan, linux-doc, Mathieu Desnoyers, Paul E. McKenney,
rcu, Steven Rostedt, kernel-team
Hi,
This is a series on top of the patch "rcu/tree: Add basic support for kfree_rcu() batching".
Link: http://lore.kernel.org/r/20190814160411.58591-1-joel@joelfernandes.org
It adds performance tests, some clean ups and removal of "lazy" RCU callbacks.
Now that kfree_rcu() is handled separately from call_rcu(), we also get rid of
kfree "lazy" handling from tree RCU as suggested by Paul which will be unused.
This also results in a nice negative delta as well.
Joel Fernandes (Google) (5):
rcu/rcuperf: Add kfree_rcu() performance Tests
rcu/tree: Add multiple in-flight batches of kfree_rcu work
rcu/tree: Add support for debug_objects debugging for kfree_rcu()
rcu: Remove kfree_rcu() special casing and lazy handling
rcu: Remove kfree_call_rcu_nobatch()
Documentation/RCU/stallwarn.txt | 13 +-
.../admin-guide/kernel-parameters.txt | 13 ++
include/linux/rcu_segcblist.h | 2 -
include/linux/rcutiny.h | 5 -
include/linux/rcutree.h | 1 -
include/trace/events/rcu.h | 32 ++--
kernel/rcu/rcu.h | 27 ---
kernel/rcu/rcu_segcblist.c | 25 +--
kernel/rcu/rcu_segcblist.h | 25 +--
kernel/rcu/rcuperf.c | 173 +++++++++++++++++-
kernel/rcu/srcutree.c | 4 +-
kernel/rcu/tiny.c | 29 ++-
kernel/rcu/tree.c | 145 ++++++++++-----
kernel/rcu/tree.h | 1 -
kernel/rcu/tree_plugin.h | 42 +----
kernel/rcu/tree_stall.h | 6 +-
16 files changed, 337 insertions(+), 206 deletions(-)
--
2.23.0.187.g17f5b7556c-goog
^ permalink raw reply
* [PATCH 5/5] rcu: Remove kfree_call_rcu_nobatch()
From: Joel Fernandes (Google) @ 2019-08-27 19:01 UTC (permalink / raw)
To: linux-kernel
Cc: Joel Fernandes (Google), byungchul.park, Josh Triplett,
Lai Jiangshan, linux-doc, Mathieu Desnoyers, Paul E. McKenney,
rcu, Steven Rostedt, kernel-team
Now that kfree_rcu() special casing have been removed from tree RCU,
remove kfree_call_rcu_nobatch() since it is not needed.
Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>
---
.../admin-guide/kernel-parameters.txt | 4 ---
include/linux/rcutiny.h | 5 ---
include/linux/rcutree.h | 1 -
kernel/rcu/rcuperf.c | 10 +-----
kernel/rcu/tree.c | 33 ++++++++-----------
5 files changed, 14 insertions(+), 39 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 24fe8aefb12c..56be0e30100b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3909,10 +3909,6 @@
Number of loops doing rcuperf.kfree_alloc_num number
of allocations and frees.
- rcuperf.kfree_no_batch= [KNL]
- Use the non-batching (less efficient) version of kfree_rcu().
- This is useful for comparing with the batched version.
-
rcuperf.nreaders= [KNL]
Set number of RCU readers. The value -1 selects
N, where N is the number of CPUs. A value
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 949841f52ec5..7aa93afa5d8d 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -39,11 +39,6 @@ static inline void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
call_rcu(head, func);
}
-static inline void kfree_call_rcu_nobatch(struct rcu_head *head, rcu_callback_t func)
-{
- call_rcu(head, func);
-}
-
void rcu_qs(void);
static inline void rcu_softirq_qs(void)
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 961b7e05d141..0b68aa952f8b 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -34,7 +34,6 @@ static inline void rcu_virt_note_context_switch(int cpu)
void synchronize_rcu_expedited(void);
void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func);
-void kfree_call_rcu_nobatch(struct rcu_head *head, rcu_callback_t func);
void rcu_barrier(void);
bool rcu_eqs_special_set(int cpu);
diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index c1e25fd10f2a..da94b89cd531 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -593,7 +593,6 @@ rcu_perf_shutdown(void *arg)
torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu().");
torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration.");
torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees.");
-torture_param(int, kfree_no_batch, 0, "Use the non-batching (slower) version of kfree_rcu().");
static struct task_struct **kfree_reader_tasks;
static int kfree_nrealthreads;
@@ -632,14 +631,7 @@ kfree_perf_thread(void *arg)
if (!alloc_ptr)
return -ENOMEM;
- if (!kfree_no_batch) {
- kfree_rcu(alloc_ptr, rh);
- } else {
- rcu_callback_t cb;
-
- cb = (rcu_callback_t)(unsigned long)offsetof(struct kfree_obj, rh);
- kfree_call_rcu_nobatch(&(alloc_ptr->rh), cb);
- }
+ kfree_rcu(alloc_ptr, rh);
}
cond_resched();
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 12c17e10f2b4..c767973d62ac 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -2777,8 +2777,10 @@ static void kfree_rcu_work(struct work_struct *work)
rcu_lock_acquire(&rcu_callback_map);
trace_rcu_invoke_kfree_callback(rcu_state.name, head, offset);
- /* Could be possible to optimize with kfree_bulk in future */
- kfree((void *)head - offset);
+ if (!WARN_ON_ONCE(!__is_kfree_rcu_offset(offset))) {
+ /* Could be optimized with kfree_bulk() in future. */
+ kfree((void *)head - offset);
+ }
rcu_lock_release(&rcu_callback_map);
cond_resched_tasks_rcu_qs();
@@ -2856,16 +2858,6 @@ static void kfree_rcu_monitor(struct work_struct *work)
spin_unlock_irqrestore(&krcp->lock, flags);
}
-/*
- * This version of kfree_call_rcu does not do batching of kfree_rcu() requests.
- * Used only by rcuperf torture test for comparison with kfree_rcu_batch().
- */
-void kfree_call_rcu_nobatch(struct rcu_head *head, rcu_callback_t func)
-{
- __call_rcu(head, func);
-}
-EXPORT_SYMBOL_GPL(kfree_call_rcu_nobatch);
-
/*
* Queue a request for lazy invocation of kfree() after a grace period.
*
@@ -2885,12 +2877,6 @@ void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
unsigned long flags;
struct kfree_rcu_cpu *krcp;
- /* kfree_call_rcu() batching requires timers to be up. If the scheduler
- * is not yet up, just skip batching and do the non-batched version.
- */
- if (rcu_scheduler_active != RCU_SCHEDULER_RUNNING)
- return kfree_call_rcu_nobatch(head, func);
-
if (debug_rcu_head_queue(head)) {
/* Probable double kfree_rcu() */
WARN_ONCE(1, "kfree_call_rcu(): Double-freed call. rcu_head %p\n",
@@ -2909,8 +2895,15 @@ void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
krcp->head = head;
/* Schedule monitor for timely drain after KFREE_DRAIN_JIFFIES. */
- if (!xchg(&krcp->monitor_todo, true))
- schedule_delayed_work(&krcp->monitor_work, KFREE_DRAIN_JIFFIES);
+ if (!xchg(&krcp->monitor_todo, true)) {
+ /* Scheduling the monitor requires scheduler/timers to be up,
+ * if it is not, just skip it. An eventual kfree_rcu() will
+ * kick it again.
+ */
+ if ((rcu_scheduler_active == RCU_SCHEDULER_RUNNING)) {
+ schedule_delayed_work(&krcp->monitor_work, KFREE_DRAIN_JIFFIES);
+ }
+ }
spin_unlock(&krcp->lock);
local_irq_restore(flags);
--
2.23.0.187.g17f5b7556c-goog
^ permalink raw reply related
* [PATCH 1/5] rcu/rcuperf: Add kfree_rcu() performance Tests
From: Joel Fernandes (Google) @ 2019-08-27 19:01 UTC (permalink / raw)
To: linux-kernel
Cc: Joel Fernandes (Google), byungchul.park, Josh Triplett,
Lai Jiangshan, linux-doc, Mathieu Desnoyers, Paul E. McKenney,
rcu, Steven Rostedt, kernel-team
This test runs kfree_rcu() in a loop to measure performance of the new
kfree_rcu() batching functionality.
The following table shows results when booting with arguments:
rcuperf.kfree_loops=20000 rcuperf.kfree_alloc_num=8000 rcuperf.kfree_rcu_test=1
In addition, rcuperf.kfree_no_batch is used to toggle the batching of
kfree_rcu()s for a test run.
patch applied GPs time (seconds)
yes 1732 14.5
no 9133 11.5
On a 16 CPU system with the above boot parameters, we see that the total
number of grace periods that elapse during the test drops from 9133 when
not batching to 1732 when batching (a 5X improvement). The kfree_rcu()
flood itself slows down a bit when batching, though, as shown.
Note that the active memory consumption during the kfree_rcu() flood
does increase to around 200-250MB due to the batching (from around 50MB
without batching). However, this memory consumption is relatively
constant. In other words, the system is able to keep up with the
kfree_rcu() load. The memory consumption comes down considerably if
KFREE_DRAIN_JIFFIES is increased from HZ/50 to HZ/80.
Also, when running the test, please disable CONFIG_DEBUG_PREEMPT and
CONFIG_PROVE_RCU for realistic comparisons with/without batching.
Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>
---
.../admin-guide/kernel-parameters.txt | 17 ++
kernel/rcu/rcuperf.c | 181 +++++++++++++++++-
2 files changed, 190 insertions(+), 8 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 79b983bedcaa..24fe8aefb12c 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3896,6 +3896,23 @@
test until boot completes in order to avoid
interference.
+ rcuperf.kfree_rcu_test= [KNL]
+ Set to measure performance of kfree_rcu() flooding.
+
+ rcuperf.kfree_nthreads= [KNL]
+ The number of threads running loops of kfree_rcu().
+
+ rcuperf.kfree_alloc_num= [KNL]
+ Number of allocations and frees done in an iteration.
+
+ rcuperf.kfree_loops= [KNL]
+ Number of loops doing rcuperf.kfree_alloc_num number
+ of allocations and frees.
+
+ rcuperf.kfree_no_batch= [KNL]
+ Use the non-batching (less efficient) version of kfree_rcu().
+ This is useful for comparing with the batched version.
+
rcuperf.nreaders= [KNL]
Set number of RCU readers. The value -1 selects
N, where N is the number of CPUs. A value
diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index 5f884d560384..c1e25fd10f2a 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -86,6 +86,7 @@ torture_param(bool, shutdown, RCUPERF_SHUTDOWN,
"Shutdown at end of performance tests.");
torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
+torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() perf test?");
static char *perf_type = "rcu";
module_param(perf_type, charp, 0444);
@@ -105,8 +106,8 @@ static atomic_t n_rcu_perf_writer_finished;
static wait_queue_head_t shutdown_wq;
static u64 t_rcu_perf_writer_started;
static u64 t_rcu_perf_writer_finished;
-static unsigned long b_rcu_perf_writer_started;
-static unsigned long b_rcu_perf_writer_finished;
+static unsigned long b_rcu_gp_test_started;
+static unsigned long b_rcu_gp_test_finished;
static DEFINE_PER_CPU(atomic_t, n_async_inflight);
#define MAX_MEAS 10000
@@ -378,10 +379,10 @@ rcu_perf_writer(void *arg)
if (atomic_inc_return(&n_rcu_perf_writer_started) >= nrealwriters) {
t_rcu_perf_writer_started = t;
if (gp_exp) {
- b_rcu_perf_writer_started =
+ b_rcu_gp_test_started =
cur_ops->exp_completed() / 2;
} else {
- b_rcu_perf_writer_started = cur_ops->get_gp_seq();
+ b_rcu_gp_test_started = cur_ops->get_gp_seq();
}
}
@@ -429,10 +430,10 @@ rcu_perf_writer(void *arg)
PERFOUT_STRING("Test complete");
t_rcu_perf_writer_finished = t;
if (gp_exp) {
- b_rcu_perf_writer_finished =
+ b_rcu_gp_test_finished =
cur_ops->exp_completed() / 2;
} else {
- b_rcu_perf_writer_finished =
+ b_rcu_gp_test_finished =
cur_ops->get_gp_seq();
}
if (shutdown) {
@@ -515,8 +516,8 @@ rcu_perf_cleanup(void)
t_rcu_perf_writer_finished -
t_rcu_perf_writer_started,
ngps,
- rcuperf_seq_diff(b_rcu_perf_writer_finished,
- b_rcu_perf_writer_started));
+ rcuperf_seq_diff(b_rcu_gp_test_finished,
+ b_rcu_gp_test_started));
for (i = 0; i < nrealwriters; i++) {
if (!writer_durations)
break;
@@ -584,6 +585,167 @@ rcu_perf_shutdown(void *arg)
return -EINVAL;
}
+/*
+ * kfree_rcu() performance tests: Start a kfree_rcu() loop on all CPUs for number
+ * of iterations and measure total time and number of GP for all iterations to complete.
+ */
+
+torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu().");
+torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration.");
+torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees.");
+torture_param(int, kfree_no_batch, 0, "Use the non-batching (slower) version of kfree_rcu().");
+
+static struct task_struct **kfree_reader_tasks;
+static int kfree_nrealthreads;
+static atomic_t n_kfree_perf_thread_started;
+static atomic_t n_kfree_perf_thread_ended;
+
+struct kfree_obj {
+ char kfree_obj[8];
+ struct rcu_head rh;
+};
+
+static int
+kfree_perf_thread(void *arg)
+{
+ int i, loop = 0;
+ long me = (long)arg;
+ struct kfree_obj *alloc_ptr;
+ u64 start_time, end_time;
+
+ VERBOSE_PERFOUT_STRING("kfree_perf_thread task started");
+ set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
+ set_user_nice(current, MAX_NICE);
+
+ start_time = ktime_get_mono_fast_ns();
+
+ if (atomic_inc_return(&n_kfree_perf_thread_started) >= kfree_nrealthreads) {
+ if (gp_exp)
+ b_rcu_gp_test_started = cur_ops->exp_completed() / 2;
+ else
+ b_rcu_gp_test_started = cur_ops->get_gp_seq();
+ }
+
+ do {
+ for (i = 0; i < kfree_alloc_num; i++) {
+ alloc_ptr = kmalloc(sizeof(struct kfree_obj), GFP_KERNEL);
+ if (!alloc_ptr)
+ return -ENOMEM;
+
+ if (!kfree_no_batch) {
+ kfree_rcu(alloc_ptr, rh);
+ } else {
+ rcu_callback_t cb;
+
+ cb = (rcu_callback_t)(unsigned long)offsetof(struct kfree_obj, rh);
+ kfree_call_rcu_nobatch(&(alloc_ptr->rh), cb);
+ }
+ }
+
+ cond_resched();
+ } while (!torture_must_stop() && ++loop < kfree_loops);
+
+ if (atomic_inc_return(&n_kfree_perf_thread_ended) >= kfree_nrealthreads) {
+ end_time = ktime_get_mono_fast_ns();
+
+ if (gp_exp)
+ b_rcu_gp_test_finished = cur_ops->exp_completed() / 2;
+ else
+ b_rcu_gp_test_finished = cur_ops->get_gp_seq();
+
+ pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld\n",
+ (unsigned long long)(end_time - start_time), kfree_loops,
+ rcuperf_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started));
+ if (shutdown) {
+ smp_mb(); /* Assign before wake. */
+ wake_up(&shutdown_wq);
+ }
+ }
+
+ torture_kthread_stopping("kfree_perf_thread");
+ return 0;
+}
+
+static void
+kfree_perf_cleanup(void)
+{
+ int i;
+
+ if (torture_cleanup_begin())
+ return;
+
+ if (kfree_reader_tasks) {
+ for (i = 0; i < kfree_nrealthreads; i++)
+ torture_stop_kthread(kfree_perf_thread,
+ kfree_reader_tasks[i]);
+ kfree(kfree_reader_tasks);
+ }
+
+ torture_cleanup_end();
+}
+
+/*
+ * shutdown kthread. Just waits to be awakened, then shuts down system.
+ */
+static int
+kfree_perf_shutdown(void *arg)
+{
+ do {
+ wait_event(shutdown_wq,
+ atomic_read(&n_kfree_perf_thread_ended) >=
+ kfree_nrealthreads);
+ } while (atomic_read(&n_kfree_perf_thread_ended) < kfree_nrealthreads);
+
+ smp_mb(); /* Wake before output. */
+
+ kfree_perf_cleanup();
+ kernel_power_off();
+ return -EINVAL;
+}
+
+static int __init
+kfree_perf_init(void)
+{
+ long i;
+ int firsterr = 0;
+
+ kfree_nrealthreads = compute_real(kfree_nthreads);
+ /* Start up the kthreads. */
+ if (shutdown) {
+ init_waitqueue_head(&shutdown_wq);
+ firsterr = torture_create_kthread(kfree_perf_shutdown, NULL,
+ shutdown_task);
+ if (firsterr)
+ goto unwind;
+ schedule_timeout_uninterruptible(1);
+ }
+
+ kfree_reader_tasks = kcalloc(kfree_nrealthreads, sizeof(kfree_reader_tasks[0]),
+ GFP_KERNEL);
+ if (kfree_reader_tasks == NULL) {
+ firsterr = -ENOMEM;
+ goto unwind;
+ }
+
+ for (i = 0; i < kfree_nrealthreads; i++) {
+ firsterr = torture_create_kthread(kfree_perf_thread, (void *)i,
+ kfree_reader_tasks[i]);
+ if (firsterr)
+ goto unwind;
+ }
+
+ while (atomic_read(&n_kfree_perf_thread_started) < kfree_nrealthreads)
+ schedule_timeout_uninterruptible(1);
+
+ torture_init_end();
+ return 0;
+
+unwind:
+ torture_init_end();
+ kfree_perf_cleanup();
+ return firsterr;
+}
+
static int __init
rcu_perf_init(void)
{
@@ -616,6 +778,9 @@ rcu_perf_init(void)
if (cur_ops->init)
cur_ops->init();
+ if (kfree_rcu_test)
+ return kfree_perf_init();
+
nrealwriters = compute_real(nwriters);
nrealreaders = compute_real(nreaders);
atomic_set(&n_rcu_perf_reader_started, 0);
--
2.23.0.187.g17f5b7556c-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox