Message ID | 20230215145425.420125-1-usama.arif@bytedance.com (mailing list archive) |
---|---|
Headers | show |
Series | Parallel CPU bringup for x86_64 | expand |
On Wed, Feb 15, 2023 at 02:54:17PM +0000, Usama Arif wrote: > The main change over v8 is dropping the patch to avoid repeated saves of MTRR > at boot time. It didn't make a difference to smpboot time and is independent > of parallel CPU bringup, so if needed can be explored in a separate patchset. > > The patches have also been rebased to v6.2-rc8 and retested and the > improvement in boot time is the same as v8. This version passes moderate torture testing. Tested-by: Paul E. McKenney <paulmck@kernel.org> > Thanks, > Usama > > Changes across versions: > v2: Cut it back to just INIT/SIPI/SIPI in parallel for now, nothing more > v3: Clean up x2apic patch, add MTRR optimisation, lock topology update > in preparation for more parallelisation. > v4: Fixes to the real mode parallelisation patch spotted by SeanC, to > avoid scribbling on initial_gs in common_cpu_up(), and to allow all > 24 bits of the physical X2APIC ID to be used. That patch still needs > a Signed-off-by from its original author, who once claimed not to > remember writing it at all. But now we've fixed it, hopefully he'll > admit it now :) > v5: rebase to v6.1 and remeasure performance, disable parallel bringup > for AMD CPUs. > v6: rebase to v6.2-rc6, disabled parallel boot on amd as a cpu bug and > reused timer calibration for secondary CPUs. > v7: [David Woodhouse] iterate over all possible CPUs to find any existing > cluster mask in alloc_clustermask. (patch 1/9) > Keep parallel AMD support enabled in AMD, using APIC ID in CPUID leaf > 0x0B (for x2APIC mode) or CPUID leaf 0x01 where 8 bits are sufficient. > Included sanity checks for APIC id from 0x0B. (patch 6/9) > Removed patch for reusing timer calibration for secondary CPUs. > commit message and code improvements. > v8: Fix CPU0 hotplug by setting up the initial_gs, initial_stack and > early_gdt_descr. > Drop trampoline lock and bail if APIC ID not found in find_cpunr. > Code comments improved and debug prints added. > v9: Drop patch to avoid repeated saves of MTRR at boot time. > rebased and retested at v6.2-rc8. > added kernel doc for no_parallel_bringup and made do_parallel_bringup > __ro_after_init. > > David Woodhouse (8): > x86/apic/x2apic: Allow CPU cluster_mask to be populated in parallel > cpu/hotplug: Move idle_thread_get() to <linux/smpboot.h> > cpu/hotplug: Add dynamic parallel bringup states before > CPUHP_BRINGUP_CPU > x86/smpboot: Reference count on smpboot_setup_warm_reset_vector() > x86/smpboot: Split up native_cpu_up into separate phases and document > them > x86/smpboot: Support parallel startup of secondary CPUs > x86/smpboot: Send INIT/SIPI/SIPI to secondary CPUs in parallel > x86/smpboot: Serialize topology updates for secondary bringup > > .../admin-guide/kernel-parameters.txt | 3 + > arch/x86/include/asm/realmode.h | 3 + > arch/x86/include/asm/smp.h | 14 +- > arch/x86/include/asm/topology.h | 2 - > arch/x86/kernel/acpi/sleep.c | 1 + > arch/x86/kernel/apic/apic.c | 2 +- > arch/x86/kernel/apic/x2apic_cluster.c | 130 ++++--- > arch/x86/kernel/cpu/common.c | 6 +- > arch/x86/kernel/head_64.S | 99 ++++- > arch/x86/kernel/smpboot.c | 350 +++++++++++++----- > arch/x86/realmode/init.c | 3 + > arch/x86/realmode/rm/trampoline_64.S | 14 + > arch/x86/xen/smp_pv.c | 4 +- > include/linux/cpuhotplug.h | 2 + > include/linux/smpboot.h | 7 + > kernel/cpu.c | 31 +- > kernel/smpboot.c | 2 +- > kernel/smpboot.h | 2 - > 18 files changed, 515 insertions(+), 160 deletions(-) > > -- > 2.25.1 >
Hello. On středa 15. února 2023 15:54:17 CET Usama Arif wrote: > The main change over v8 is dropping the patch to avoid repeated saves of MTRR > at boot time. It didn't make a difference to smpboot time and is independent > of parallel CPU bringup, so if needed can be explored in a separate patchset. > > The patches have also been rebased to v6.2-rc8 and retested and the > improvement in boot time is the same as v8. > > Thanks, > Usama > > Changes across versions: > v2: Cut it back to just INIT/SIPI/SIPI in parallel for now, nothing more > v3: Clean up x2apic patch, add MTRR optimisation, lock topology update > in preparation for more parallelisation. > v4: Fixes to the real mode parallelisation patch spotted by SeanC, to > avoid scribbling on initial_gs in common_cpu_up(), and to allow all > 24 bits of the physical X2APIC ID to be used. That patch still needs > a Signed-off-by from its original author, who once claimed not to > remember writing it at all. But now we've fixed it, hopefully he'll > admit it now :) > v5: rebase to v6.1 and remeasure performance, disable parallel bringup > for AMD CPUs. > v6: rebase to v6.2-rc6, disabled parallel boot on amd as a cpu bug and > reused timer calibration for secondary CPUs. > v7: [David Woodhouse] iterate over all possible CPUs to find any existing > cluster mask in alloc_clustermask. (patch 1/9) > Keep parallel AMD support enabled in AMD, using APIC ID in CPUID leaf > 0x0B (for x2APIC mode) or CPUID leaf 0x01 where 8 bits are sufficient. > Included sanity checks for APIC id from 0x0B. (patch 6/9) > Removed patch for reusing timer calibration for secondary CPUs. > commit message and code improvements. > v8: Fix CPU0 hotplug by setting up the initial_gs, initial_stack and > early_gdt_descr. > Drop trampoline lock and bail if APIC ID not found in find_cpunr. > Code comments improved and debug prints added. > v9: Drop patch to avoid repeated saves of MTRR at boot time. > rebased and retested at v6.2-rc8. > added kernel doc for no_parallel_bringup and made do_parallel_bringup > __ro_after_init. > > David Woodhouse (8): > x86/apic/x2apic: Allow CPU cluster_mask to be populated in parallel > cpu/hotplug: Move idle_thread_get() to <linux/smpboot.h> > cpu/hotplug: Add dynamic parallel bringup states before > CPUHP_BRINGUP_CPU > x86/smpboot: Reference count on smpboot_setup_warm_reset_vector() > x86/smpboot: Split up native_cpu_up into separate phases and document > them > x86/smpboot: Support parallel startup of secondary CPUs > x86/smpboot: Send INIT/SIPI/SIPI to secondary CPUs in parallel > x86/smpboot: Serialize topology updates for secondary bringup > > .../admin-guide/kernel-parameters.txt | 3 + > arch/x86/include/asm/realmode.h | 3 + > arch/x86/include/asm/smp.h | 14 +- > arch/x86/include/asm/topology.h | 2 - > arch/x86/kernel/acpi/sleep.c | 1 + > arch/x86/kernel/apic/apic.c | 2 +- > arch/x86/kernel/apic/x2apic_cluster.c | 130 ++++--- > arch/x86/kernel/cpu/common.c | 6 +- > arch/x86/kernel/head_64.S | 99 ++++- > arch/x86/kernel/smpboot.c | 350 +++++++++++++----- > arch/x86/realmode/init.c | 3 + > arch/x86/realmode/rm/trampoline_64.S | 14 + > arch/x86/xen/smp_pv.c | 4 +- > include/linux/cpuhotplug.h | 2 + > include/linux/smpboot.h | 7 + > kernel/cpu.c | 31 +- > kernel/smpboot.c | 2 +- > kernel/smpboot.h | 2 - > 18 files changed, 515 insertions(+), 160 deletions(-) I've applied this to the v6.2 kernel, and suspend/resume broke on my Ryzen 5950X desktop. The machine suspends just fine, but on resume the screen stays blank, and there's no visible disk I/O. Reverting the series brings suspend/resume back to working state.
On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: > > I've applied this to the v6.2 kernel, and suspend/resume broke on my > Ryzen 5950X desktop. The machine suspends just fine, but on resume > the screen stays blank, and there's no visible disk I/O. > > Reverting the series brings suspend/resume back to working state. Hm, thanks. What if you add 'no_parallel_bringup' on the command line? Is that using X2APIC? If so, what about 'nox2apic' on the command line?
Hello. Thank you for your reply. On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: > > > > I've applied this to the v6.2 kernel, and suspend/resume broke on my > > Ryzen 5950X desktop. The machine suspends just fine, but on resume > > the screen stays blank, and there's no visible disk I/O. > > > > Reverting the series brings suspend/resume back to working state. > > Hm, thanks. What if you add 'no_parallel_bringup' on the command line? If the `no_parallel_bringup` param is added, the suspend/resume works. > Is that using X2APIC? Probably? ``` $ dmesg | grep -i x2apic [ 0.632740] x2apic: IRQ remapping doesn't support X2APIC mode ``` > If so, what about 'nox2apic' on the command line? If `no_parallel_bringup` is removed and `nox2apic` is added, then the `x2apic: …` stuff disappears from dmesg, but suspend/resume remains broken.
On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: > Hello. > > Thank you for your reply. > > On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: > > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: > > > > > > I've applied this to the v6.2 kernel, and suspend/resume broke on > > > my > > > Ryzen 5950X desktop. The machine suspends just fine, but on > > > resume > > > the screen stays blank, and there's no visible disk I/O. > > > > > > Reverting the series brings suspend/resume back to working state. > > > > Hm, thanks. What if you add 'no_parallel_bringup' on the command > > line? > > If the `no_parallel_bringup` param is added, the suspend/resume > works. Thanks for the testing. Can I ask you to do one further test: apply the series only as far as patch 6/8 'x86/smpboot: Support parallel startup of secondary CPUs'. That will do the new startup asm sequence where each CPU finds its own per-cpu data so it *could* work in parallel, but doesn't actually do the bringup in parallel yet. Does your box have a proper serial port?
Hello. On 20.02.2023 21:31, David Woodhouse wrote: > On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >> > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >> > > >> > > I've applied this to the v6.2 kernel, and suspend/resume broke on >> > > my >> > > Ryzen 5950X desktop. The machine suspends just fine, but on >> > > resume >> > > the screen stays blank, and there's no visible disk I/O. >> > > >> > > Reverting the series brings suspend/resume back to working state. >> > >> > Hm, thanks. What if you add 'no_parallel_bringup' on the command >> > line? >> >> If the `no_parallel_bringup` param is added, the suspend/resume >> works. > > Thanks for the testing. Can I ask you to do one further test: apply the > series only as far as patch 6/8 'x86/smpboot: Support parallel startup > of secondary CPUs'. > > That will do the new startup asm sequence where each CPU finds its own > per-cpu data so it *could* work in parallel, but doesn't actually do > the bringup in parallel yet. With patches 1 to 6 (including) applied and no extra cmdline params added the resume doesn't work. > Does your box have a proper serial port? No, sorry. I know it'd help with getting logs, and I do have a serial-to-USB cable that I use for another machine, but in this one the port is not routed to outside. I think I can put a header there as the motherboard does have pins, but I'd have to buy one first. In theory, I can do that, but that won't happen within the next few weeks. P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core when using smp boot patchset". Probably, he can reply to this thread and provide more details.
Hello. In my case, admittedly, the error does not occur, while I have information from a friend that AMD FX 6300 only shows 1 core when using smp boot patchset, so mentioned Oleksandr. Probably soon the friend will join the discussion and will be able to provide more information. W dniu 20.02.2023 o 22:23, Oleksandr Natalenko pisze: > Hello. > > On 20.02.2023 21:31, David Woodhouse wrote: >> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>> > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>> > > >>> > > I've applied this to the v6.2 kernel, and suspend/resume broke on >>> > > my >>> > > Ryzen 5950X desktop. The machine suspends just fine, but on >>> > > resume >>> > > the screen stays blank, and there's no visible disk I/O. >>> > > >>> > > Reverting the series brings suspend/resume back to working state. >>> > >>> > Hm, thanks. What if you add 'no_parallel_bringup' on the command >>> > line? >>> >>> If the `no_parallel_bringup` param is added, the suspend/resume >>> works. >> >> Thanks for the testing. Can I ask you to do one further test: apply the >> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >> of secondary CPUs'. >> >> That will do the new startup asm sequence where each CPU finds its own >> per-cpu data so it *could* work in parallel, but doesn't actually do >> the bringup in parallel yet. > > With patches 1 to 6 (including) applied and no extra cmdline params > added the resume doesn't work. > >> Does your box have a proper serial port? > > No, sorry. I know it'd help with getting logs, and I do have a > serial-to-USB cable that I use for another machine, but in this one > the port is not routed to outside. I think I can put a header there as > the motherboard does have pins, but I'd have to buy one first. In > theory, I can do that, but that won't happen within the next few weeks. > > P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS > can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core > when using smp boot patchset". Probably, he can reply to this thread > and provide more details. >
On 20 February 2023 21:23:38 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >Hello. > >On 20.02.2023 21:31, David Woodhouse wrote: >> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>> > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>> > > >>> > > I've applied this to the v6.2 kernel, and suspend/resume broke on >>> > > my >>> > > Ryzen 5950X desktop. The machine suspends just fine, but on >>> > > resume >>> > > the screen stays blank, and there's no visible disk I/O. >>> > > >>> > > Reverting the series brings suspend/resume back to working state. >>> > >>> > Hm, thanks. What if you add 'no_parallel_bringup' on the command >>> > line? >>> >>> If the `no_parallel_bringup` param is added, the suspend/resume >>> works. >> >> Thanks for the testing. Can I ask you to do one further test: apply the >> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >> of secondary CPUs'. >> >> That will do the new startup asm sequence where each CPU finds its own >> per-cpu data so it *could* work in parallel, but doesn't actually do >> the bringup in parallel yet. > >With patches 1 to 6 (including) applied and no extra cmdline params added the resume doesn't work. Hm. Kim, is there some weirdness with the way AMD CPUs get their APIC ID in CPUID 0x1? Especially after resume? Perhaps we turn it off for any AMD CPU that doesn't have X2APIC and CPUID 0xB? >> Does your box have a proper serial port? > >No, sorry. I know it'd help with getting logs, and I do have a serial-to-USB cable that I use for another machine, but in this one the port is not routed to outside. I think I can put a header there as the motherboard does have pins, but I'd have to buy one first. In theory, I can do that, but that won't happen within the next few weeks. > >P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core when using smp boot patchset". Probably, he can reply to this thread and provide more details. >
Hello. In my case, admittedly, the error does not occur, while I have information from a friend that AMD FX 6300 only shows 1 core when using smp boot patchset, so mentioned Oleksandr. Probably soon friend will join the discussion and will be able to provide more information. W dniu 20.02.2023 o 22:23, Oleksandr Natalenko pisze: > Hello. > > On 20.02.2023 21:31, David Woodhouse wrote: >> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>> > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>> > > >>> > > I've applied this to the v6.2 kernel, and suspend/resume broke on >>> > > my >>> > > Ryzen 5950X desktop. The machine suspends just fine, but on >>> > > resume >>> > > the screen stays blank, and there's no visible disk I/O. >>> > > >>> > > Reverting the series brings suspend/resume back to working state. >>> > >>> > Hm, thanks. What if you add 'no_parallel_bringup' on the command >>> > line? >>> >>> If the `no_parallel_bringup` param is added, the suspend/resume >>> works. >> >> Thanks for the testing. Can I ask you to do one further test: apply the >> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >> of secondary CPUs'. >> >> That will do the new startup asm sequence where each CPU finds its own >> per-cpu data so it *could* work in parallel, but doesn't actually do >> the bringup in parallel yet. > > With patches 1 to 6 (including) applied and no extra cmdline params > added the resume doesn't work. > >> Does your box have a proper serial port? > > No, sorry. I know it'd help with getting logs, and I do have a > serial-to-USB cable that I use for another machine, but in this one > the port is not routed to outside. I think I can put a header there as > the motherboard does have pins, but I'd have to buy one first. In > theory, I can do that, but that won't happen within the next few weeks. > > P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS > can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core > when using smp boot patchset". Probably, he can reply to this thread > and provide more details. >
On 20/02/2023 21:23, Oleksandr Natalenko wrote: > Hello. > > On 20.02.2023 21:31, David Woodhouse wrote: >> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>> > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>> > > >>> > > I've applied this to the v6.2 kernel, and suspend/resume broke on >>> > > my >>> > > Ryzen 5950X desktop. The machine suspends just fine, but on >>> > > resume >>> > > the screen stays blank, and there's no visible disk I/O. >>> > > >>> > > Reverting the series brings suspend/resume back to working state. >>> > >>> > Hm, thanks. What if you add 'no_parallel_bringup' on the command >>> > line? >>> >>> If the `no_parallel_bringup` param is added, the suspend/resume >>> works. >> >> Thanks for the testing. Can I ask you to do one further test: apply the >> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >> of secondary CPUs'. >> >> That will do the new startup asm sequence where each CPU finds its own >> per-cpu data so it *could* work in parallel, but doesn't actually do >> the bringup in parallel yet. > > With patches 1 to 6 (including) applied and no extra cmdline params > added the resume doesn't work. > >> Does your box have a proper serial port? > > No, sorry. I know it'd help with getting logs, and I do have a > serial-to-USB cable that I use for another machine, but in this one the > port is not routed to outside. I think I can put a header there as the > motherboard does have pins, but I'd have to buy one first. In theory, I > can do that, but that won't happen within the next few weeks. > > P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS > can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core > when using smp boot patchset". Probably, he can reply to this thread and > provide more details. > Hi Oleksandr, So for initial boot, do all CPUs comes up for you when parallel smp boot is enabled or only 1? I don't have access to Ryzen hardware so can only say from code, but it would be weird if initial boot is fine but resume is broken if the same code path is being taken. Thanks, Usama
Hello. On pondělí 20. února 2023 23:23:43 CET Usama Arif wrote: > So for initial boot, do all CPUs comes up for you when parallel smp boot > is enabled or only 1? All the CPUs come up during the initial boot. > I don't have access to Ryzen hardware so can only say from code, but it > would be weird if initial boot is fine but resume is broken if the same > code path is being taken.
On 2/20/23 3:39 PM, David Woodhouse wrote: > On 20 February 2023 21:23:38 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >> Hello. >> >> On 20.02.2023 21:31, David Woodhouse wrote: >>> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>>>> On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>>>>> >>>>>> I've applied this to the v6.2 kernel, and suspend/resume broke on >>>>>> my >>>>>> Ryzen 5950X desktop. The machine suspends just fine, but on >>>>>> resume >>>>>> the screen stays blank, and there's no visible disk I/O. >>>>>> >>>>>> Reverting the series brings suspend/resume back to working state. >>>>> >>>>> Hm, thanks. What if you add 'no_parallel_bringup' on the command >>>>> line? >>>> >>>> If the `no_parallel_bringup` param is added, the suspend/resume >>>> works. >>> >>> Thanks for the testing. Can I ask you to do one further test: apply the >>> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >>> of secondary CPUs'. >>> >>> That will do the new startup asm sequence where each CPU finds its own >>> per-cpu data so it *could* work in parallel, but doesn't actually do >>> the bringup in parallel yet. >> >> With patches 1 to 6 (including) applied and no extra cmdline params added the resume doesn't work. > > Hm. Kim, is there some weirdness with the way AMD CPUs get their APIC ID in CPUID 0x1? Especially after resume? Not to my knowledge. Mario? > Perhaps we turn it off for any AMD CPU that doesn't have X2APIC and CPUID 0xB? Perhaps. >>> Does your box have a proper serial port? >> >> No, sorry. I know it'd help with getting logs, and I do have a serial-to-USB cable that I use for another machine, but in this one the port is not routed to outside. I think I can put a header there as the motherboard does have pins, but I'd have to buy one first. In theory, I can do that, but that won't happen within the next few weeks. >> >> P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core when using smp boot patchset". Probably, he can reply to this thread and provide more details. >> I ran mem/disk versions of 'sudo rtcwake --mode mem -s 60' on my Rome server, and multiple suspend/resumes succeeded, and with all CPUs, but then the NETDEV WATCHDOG fired - not sure if it's related: ... [ 2751.335882] smpboot: Booting Node 1 Processor 127 APIC 0x7f [ 2751.340124] ACPI: \_SB_.C07F: Found 2 idle states [ 2751.392591] CPU127 is up [ 2751.455650] nvme nvme0: 7/0/0 default/read/poll queues [ 2751.466112] e1000e 0000:41:00.0 enp65s0: NIC Link is Up 1000 Mbps Full Duplex, Flow Control: Rx/Tx [ 2751.635573] PM: Cannot find swap device, try swapon -a [ 2751.641315] PM: Cannot get swap writer [ 2751.926594] ata7: SATA link up 6.0 Gbps (SStatus 133 SControl 300) [ 2751.928527] ata7.00: supports DRM functions and may not be fully accessible [ 2751.933208] ata7.00: supports DRM functions and may not be fully accessible [ 2751.937797] ata7.00: configured for UDMA/133 [ 2751.948170] ata7.00: Enabling discard_zeroes_data [ 2762.428397] PM: hibernation: Basic memory bitmaps freed [ 2762.429004] OOM killer enabled. [ 2762.429008] Restarting tasks ... done. [ 2762.433155] PM: hibernation: hibernation exit [ 2762.447318] systemd-journald[1387]: Sent WATCHDOG=1 notification. [ 2830.013372] systemd-journald[1387]: Sent WATCHDOG=1 notification. [ 2919.099718] systemd-journald[1387]: Sent WATCHDOG=1 notification. [ 2992.729927] ------------[ cut here ]------------ [ 2992.729965] NETDEV WATCHDOG: enp65s0 (e1000e): transmit queue 0 timed out [ 2992.730012] WARNING: CPU: 0 PID: 0 at net/sched/sch_generic.c:525 dev_watchdog+0x234/0x250 [ 2992.730032] Modules linked in: intel_rapl_msr intel_rapl_common amd64_edac edac_mce_amd rapl ipmi_si wmi_bmof binfmt_misc kvm_amd kvm nls_iso8859_1 joydev input_leds k10temp mac_hid sch_fq_codel dm_multipath scsi_dh_rdac scsi_dh_emc scsi_dh_alua ipmi_devintf ipmi_msghandler msr ramoops reed_solomon efi_pstore ip_tables x_tables autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq raid1 raid0 multipath linear ast i2c_algo_bit drm_shmem_helper drm_kms_helper syscopyarea sysfillrect crct10dif_pclmul crc32_pclmul ghash_clmulni_intel sha512_ssse3 aesni_intel crypto_simd cryptd hid_generic sysimgblt nvme usbhid ahci drm libahci hid nvme_core i2c_piix4 wmi [ 2992.730711] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 6.2.0-rc8+ #20 [ 2992.730720] Hardware name: AMD Corporation ETHANOL_X/ETHANOL_X, BIOS RXM1007C 11/08/2021 [ 2992.730727] RIP: 0010:dev_watchdog+0x234/0x250 [ 2992.730732] Code: 00 e9 12 ff ff ff 4c 89 e7 c6 05 6f d5 42 01 01 e8 c1 55 f8 ff 44 89 f1 4c 89 e6 48 c7 c7 28 ff 88 b1 48 89 c2 e8 85 fc 1c 00 <0f> 0b e9 22 ff ff ff 0f 1f 44 00 00 e9 0b ff ff ff 66 66 2e 0f 1f [ 2992.730740] RSP: 0018:ffffbf6100003e30 EFLAGS: 00010286 [ 2992.730754] RAX: 0000000000000000 RBX: ffff9a8606da8550 RCX: 0000000000000000 [ 2992.730764] RDX: 0000000000000103 RSI: ffffffffb1741bcc RDI: 00000000ffffffff [ 2992.730770] RBP: ffffbf6100003e50 R08: 0000000000000000 R09: 00000000ffefffff [ 2992.730775] R10: ffffbf6100003ca8 R11: ffff9b038d9fd668 R12: ffff9a8606da8000 [ 2992.730780] R13: ffff9a8606da8460 R14: 0000000000000000 R15: ffff9ac346fe2480 [ 2992.730787] FS: 0000000000000000(0000) GS:ffff9ac346e00000(0000) knlGS:0000000000000000 [ 2992.730788] systemd-journald[1387]: Compressed data object 717 -> 433 using ZSTD [ 2992.730797] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2992.730804] CR2: 00007f4c419a0890 CR3: 0008004e47412003 CR4: 0000000000770ef0 [ 2992.730812] PKRU: 55555554 [ 2992.730819] Call Trace: [ 2992.730826] <IRQ> [ 2992.730840] ? __pfx_dev_watchdog+0x10/0x10 [ 2992.730852] call_timer_fn+0xac/0x250 [ 2992.730868] ? __pfx_dev_watchdog+0x10/0x10 [ 2992.730876] __run_timers+0x22d/0x2e0 [ 2992.730884] ? seqcount_lockdep_reader_access.constprop.0+0x45/0x60 [ 2992.730893] ? ktime_get+0x28/0xc0 [ 2992.730903] ? __pfx_read_tsc+0x10/0x10 [ 2992.730915] ? ktime_get+0x56/0xc0 [ 2992.730922] ? sched_clock+0xd/0x20 [ 2992.730930] ? sched_clock_cpu+0x14/0xd0 [ 2992.730941] run_timer_softirq+0x33/0x60 [ 2992.730947] __do_softirq+0x12f/0x380 [ 2992.730960] __irq_exit_rcu+0xaf/0x120 [ 2992.730970] irq_exit_rcu+0x12/0x20 [ 2992.730976] sysvec_apic_timer_interrupt+0xb4/0xd0 [ 2992.730984] </IRQ> [ 2992.730989] <TASK> [ 2992.730993] asm_sysvec_apic_timer_interrupt+0x1f/0x30 [ 2992.731004] RIP: 0010:cpuidle_enter_state+0x12d/0x4d0 [ 2992.731015] Code: 00 31 ff e8 e5 c0 45 ff 80 7d d7 00 74 16 9c 58 0f 1f 40 00 f6 c4 02 0f 85 7b 03 00 00 31 ff e8 99 de 4d ff fb 0f 1f 44 00 00 <45> 85 ff 0f 88 d1 01 00 00 49 63 d7 4c 89 f1 48 2b 4d c8 48 8d 04 [ 2992.731018] RSP: 0018:ffffffffb1a03dd8 EFLAGS: 00000246 [ 2992.731024] RAX: ffff9ac346e00000 RBX: ffff9ac4ec3ce400 RCX: 000000000000001f [ 2992.731027] RDX: 0000000000000000 RSI: ffffffffb1741bcc RDI: ffffffffb17470fa [ 2992.731035] RBP: ffffffffb1a03e10 R08: 000002b8cc9a617d R09: 000002b8c7e0b83a [ 2992.731041] R10: 000000000002bc82 R11: ffff9ac346ff2d44 R12: 0000000000000002 [ 2992.731048] R13: ffffffffb1f60bc0 R14: 000002b8cc9a617d R15: 0000000000000002 [ 2992.731059] ? cpuidle_enter_state+0x10b/0x4d0 [ 2992.731067] cpuidle_enter+0x32/0x50 [ 2992.731072] call_cpuidle+0x23/0x50 [ 2992.731080] do_idle+0x1dc/0x250 [ 2992.731090] cpu_startup_entry+0x24/0x30 [ 2992.731096] rest_init+0x108/0x110 [ 2992.731101] arch_call_rest_init+0x12/0x35 [ 2992.731114] start_kernel+0x6f3/0x71d [ 2992.731120] x86_64_start_reservations+0x28/0x2e [ 2992.731127] x86_64_start_kernel+0x80/0x8a [ 2992.731133] secondary_startup_64_no_verify+0x186/0x18b [ 2992.731151] </TASK> [ 2992.731158] ---[ end trace 0000000000000000 ]--- [ 2992.731371] e1000e 0000:41:00.0 enp65s0: Reset adapter unexpectedly [ 2992.870854] systemd-journald[1387]: Successfully sent stream file descriptor to service manager. [ 2996.338900] e1000e 0000:41:00.0 enp65s0: NIC Link is Up 1000 Mbps Full Duplex, Flow Control: Rx/Tx Thanks, Kim
On Mon, 2023-02-20 at 17:23 -0600, Kim Phillips wrote: > On 2/20/23 3:39 PM, David Woodhouse wrote: > > On 20 February 2023 21:23:38 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: > > > Hello. > > > > > > On 20.02.2023 21:31, David Woodhouse wrote: > > > > On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: > > > > > On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: > > > > > > On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: > > > > > > > > > > > > > > I've applied this to the v6.2 kernel, and suspend/resume broke on > > > > > > > my > > > > > > > Ryzen 5950X desktop. The machine suspends just fine, but on > > > > > > > resume > > > > > > > the screen stays blank, and there's no visible disk I/O. > > > > > > > > > > > > > > Reverting the series brings suspend/resume back to working state. > > > > > > > > > > > > Hm, thanks. What if you add 'no_parallel_bringup' on the command > > > > > > line? > > > > > > > > > > If the `no_parallel_bringup` param is added, the suspend/resume > > > > > works. > > > > > > > > Thanks for the testing. Can I ask you to do one further test: apply the > > > > series only as far as patch 6/8 'x86/smpboot: Support parallel startup > > > > of secondary CPUs'. > > > > > > > > That will do the new startup asm sequence where each CPU finds its own > > > > per-cpu data so it *could* work in parallel, but doesn't actually do > > > > the bringup in parallel yet. > > > > > > With patches 1 to 6 (including) applied and no extra cmdline > > > params added the resume doesn't work. > > > > Hm. Kim, is there some weirdness with the way AMD CPUs get their > > APIC ID in CPUID 0x1? Especially after resume? > > Not to my knowledge. Mario? Oleksandr, please could you show the output of 'cpuid' after a successful resume? I'm particularly looking for this part... $ sudo cpuid | grep -A1 1/ebx miscellaneous (1/ebx): process local APIC physical ID = 0x0 (0) -- miscellaneous (1/ebx): process local APIC physical ID = 0x2 (2) ... > > Perhaps we turn it off for any AMD CPU that doesn't have X2APIC and CPUID 0xB? > > Perhaps. > > > > > Does your box have a proper serial port? > > > > > > No, sorry. I know it'd help with getting logs, and I do have a serial-to-USB cable that I use for another machine, but in this one the port is not routed to outside. I think I can put a header there as the motherboard does have pins, but I'd have to buy one first. In theory, I can do that, but that won't happen within the next few weeks. > > > > > > P.S. Piotr Gorski (in Cc) also reported this: "My friend from CachyOS can confirm bugs with smpboot patches. AMD FX 6300 only shows 1 core when using smp boot patchset". Probably, he can reply to this thread and provide more details. > > > > > I ran mem/disk versions of 'sudo rtcwake --mode mem -s 60' > on my Rome server, and multiple suspend/resumes succeeded, and > with all CPUs, but then the NETDEV WATCHDOG fired - not sure > if it's related: I suspect not.
On 2/20/23 5:30 PM, David Woodhouse wrote: > On Mon, 2023-02-20 at 17:23 -0600, Kim Phillips wrote: >> On 2/20/23 3:39 PM, David Woodhouse wrote: >>> On 20 February 2023 21:23:38 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >>>> On 20.02.2023 21:31, David Woodhouse wrote: >>>>> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>>>>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>>>>>> On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>>>>>>> >>>>>>>> I've applied this to the v6.2 kernel, and suspend/resume broke on >>>>>>>> my >>>>>>>> Ryzen 5950X desktop. The machine suspends just fine, but on >>>>>>>> resume >>>>>>>> the screen stays blank, and there's no visible disk I/O. >>>>>>>> >>>>>>>> Reverting the series brings suspend/resume back to working state. >>>>>>> >>>>>>> Hm, thanks. What if you add 'no_parallel_bringup' on the command >>>>>>> line? >>>>>> >>>>>> If the `no_parallel_bringup` param is added, the suspend/resume >>>>>> works. >>>>> >>>>> Thanks for the testing. Can I ask you to do one further test: apply the >>>>> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >>>>> of secondary CPUs'. >>>>> >>>>> That will do the new startup asm sequence where each CPU finds its own >>>>> per-cpu data so it *could* work in parallel, but doesn't actually do >>>>> the bringup in parallel yet. >>>> >>>> With patches 1 to 6 (including) applied and no extra cmdline >>>> params added the resume doesn't work. >>> >>> Hm. Kim, is there some weirdness with the way AMD CPUs get their >>> APIC ID in CPUID 0x1? Especially after resume? >> >> Not to my knowledge. Mario? I tested v9-up-to-6/8 on a Ryzen 3000 that passed your between-v6 & v7 tree commits (ce7e2d1e046a for the parallel-6.2-rc6-part1 tag and 17bbd12ee03 for parallel-6.2-rc6), and it, too, fails to resume v9-up-to-6/8 after suspend. > Oleksandr, please could you show the output of 'cpuid' after a > successful resume? I'm particularly looking for this part... > > > $ sudo cpuid | grep -A1 1/ebx > miscellaneous (1/ebx): > process local APIC physical ID = 0x0 (0) > -- > miscellaneous (1/ebx): > process local APIC physical ID = 0x2 (2) > ... The Ryzens have a different pattern it seems: $ sudo cpuid | grep -A1 \(1/ebx miscellaneous (1/ebx): process local APIC physical ID = 0x0 (0) -- miscellaneous (1/ebx): process local APIC physical ID = 0x1 (1) -- miscellaneous (1/ebx): process local APIC physical ID = 0x2 (2) -- miscellaneous (1/ebx): process local APIC physical ID = 0x3 (3) -- miscellaneous (1/ebx): process local APIC physical ID = 0x4 (4) -- miscellaneous (1/ebx): process local APIC physical ID = 0x5 (5) -- miscellaneous (1/ebx): process local APIC physical ID = 0x6 (6) -- miscellaneous (1/ebx): process local APIC physical ID = 0x7 (7) I tested the v7 series on Ryzen, it also fails, so Ryzen users were last known good with those two aforementioned commits on your tree: git://git.infradead.org/users/dwmw2/linux.git Thanks, Kim
On 21 February 2023 04:20:41 GMT, Kim Phillips <kim.phillips@amd.com> wrote: >On 2/20/23 5:30 PM, David Woodhouse wrote: >> On Mon, 2023-02-20 at 17:23 -0600, Kim Phillips wrote: >>> On 2/20/23 3:39 PM, David Woodhouse wrote: >>>> On 20 February 2023 21:23:38 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >>>>> On 20.02.2023 21:31, David Woodhouse wrote: >>>>>> On Mon, 2023-02-20 at 17:40 +0100, Oleksandr Natalenko wrote: >>>>>>> On pondělí 20. února 2023 17:20:13 CET David Woodhouse wrote: >>>>>>>> On Mon, 2023-02-20 at 17:08 +0100, Oleksandr Natalenko wrote: >>>>>>>>> >>>>>>>>> I've applied this to the v6.2 kernel, and suspend/resume broke on >>>>>>>>> my >>>>>>>>> Ryzen 5950X desktop. The machine suspends just fine, but on >>>>>>>>> resume >>>>>>>>> the screen stays blank, and there's no visible disk I/O. >>>>>>>>> >>>>>>>>> Reverting the series brings suspend/resume back to working state. >>>>>>>> >>>>>>>> Hm, thanks. What if you add 'no_parallel_bringup' on the command >>>>>>>> line? >>>>>>> >>>>>>> If the `no_parallel_bringup` param is added, the suspend/resume >>>>>>> works. >>>>>> >>>>>> Thanks for the testing. Can I ask you to do one further test: apply the >>>>>> series only as far as patch 6/8 'x86/smpboot: Support parallel startup >>>>>> of secondary CPUs'. >>>>>> >>>>>> That will do the new startup asm sequence where each CPU finds its own >>>>>> per-cpu data so it *could* work in parallel, but doesn't actually do >>>>>> the bringup in parallel yet. >>>>> >>>>> With patches 1 to 6 (including) applied and no extra cmdline >>>>> params added the resume doesn't work. >>>> >>>> Hm. Kim, is there some weirdness with the way AMD CPUs get their >>>> APIC ID in CPUID 0x1? Especially after resume? >>> >>> Not to my knowledge. Mario? > >I tested v9-up-to-6/8 on a Ryzen 3000 that passed your between-v6 & v7 >tree commits (ce7e2d1e046a for the parallel-6.2-rc6-part1 tag >and 17bbd12ee03 for parallel-6.2-rc6), and it, too, fails to resume >v9-up-to-6/8 after suspend. > >> Oleksandr, please could you show the output of 'cpuid' after a >> successful resume? I'm particularly looking for this part... >> >> >> $ sudo cpuid | grep -A1 1/ebx >> miscellaneous (1/ebx): >> process local APIC physical ID = 0x0 (0) >> -- >> miscellaneous (1/ebx): >> process local APIC physical ID = 0x2 (2) >> ... > >The Ryzens have a different pattern it seems: > >$ sudo cpuid | grep -A1 \(1/ebx > miscellaneous (1/ebx): > process local APIC physical ID = 0x0 (0) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x1 (1) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x2 (2) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x3 (3) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x4 (4) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x5 (5) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x6 (6) >-- > miscellaneous (1/ebx): > process local APIC physical ID = 0x7 (7) > > >I tested the v7 series on Ryzen, it also fails, so >Ryzen users were last known good with those two >aforementioned commits on your tree: > >git://git.infradead.org/users/dwmw2/linux.git That was when it was only using (and validating) CPUID 0xB and never trusting CPUID 0x1, right?
On 21.02.2023 00:30, David Woodhouse wrote: > Oleksandr, please could you show the output of 'cpuid' after a > successful resume? I'm particularly looking for this part... > > > $ sudo cpuid | grep -A1 1/ebx > miscellaneous (1/ebx): > process local APIC physical ID = 0x0 (0) > -- > miscellaneous (1/ebx): > process local APIC physical ID = 0x2 (2) > ... For me this command doesn't produce any output. Also, no output from the command Kim used in response to you. With no `grep` it just dumps a table of raw hex data. It's `msr-tools` 1.3-4 from Arch. Should I run this command on a patched kernel booted with `no_parallel_bringup`, or on unpatched kernel (if that makes any difference)?
On 21 February 2023 07:27:13 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >On 21.02.2023 00:30, David Woodhouse wrote: >> Oleksandr, please could you show the output of 'cpuid' after a >> successful resume? I'm particularly looking for this part... >> >> >> $ sudo cpuid | grep -A1 1/ebx >> miscellaneous (1/ebx): >> process local APIC physical ID = 0x0 (0) >> -- >> miscellaneous (1/ebx): >> process local APIC physical ID = 0x2 (2) >> ... > >For me this command doesn't produce any output. Also, no output from the command Kim used in response to you. With no `grep` it just dumps a table of raw hex data. I'll take the hex please. >It's `msr-tools` 1.3-4 from Arch. Should I run this command on a patched kernel booted with `no_parallel_bringup`, or on unpatched kernel (if that makes any difference)? Either works as long as it's after a resume that wouldn't have worked. Thanks.
On 21.02.2023 08:53, David Woodhouse wrote: > On 21 February 2023 07:27:13 GMT, Oleksandr Natalenko > <oleksandr@natalenko.name> wrote: >> On 21.02.2023 00:30, David Woodhouse wrote: >>> Oleksandr, please could you show the output of 'cpuid' after a >>> successful resume? I'm particularly looking for this part... >>> >>> >>> $ sudo cpuid | grep -A1 1/ebx >>> miscellaneous (1/ebx): >>> process local APIC physical ID = 0x0 (0) >>> -- >>> miscellaneous (1/ebx): >>> process local APIC physical ID = 0x2 (2) >>> ... >> >> For me this command doesn't produce any output. Also, no output from >> the command Kim used in response to you. With no `grep` it just dumps >> a table of raw hex data. > > I'll take the hex please. Please see here: http://ix.io/4oLm >> It's `msr-tools` 1.3-4 from Arch. Should I run this command on a >> patched kernel booted with `no_parallel_bringup`, or on unpatched >> kernel (if that makes any difference)? > > Either works as long as it's after a resume that wouldn't have worked. > Thanks. OK, I'm on an unpatched kernel now.
On Tue, 2023-02-21 at 09:05 +0100, Oleksandr Natalenko wrote: > > Please see here: http://ix.io/4oLm Was that just for one CPU? Can we have them all please? The interesting part is the line starting 00000001. We're looking at the top 8 bits of EBX: Leaf Subleaf EAX EBX ECX EDX 00000000 00000000: 00000010 .... 68747541 Auth 444d4163 cAMD 69746e65 enti 00000001 00000000: 00a20f12 .... 00200800 .. . 7ef8320b .2.~ 178bfbff .... ↑↑ So the first CPU is CPU0. Could have told you that... what about the others? :) If anyone can reproduce this with a serial port, can you try this? From 98ad11d0fb88f081f49f7b1496420dbfbeff8833 Mon Sep 17 00:00:00 2001 From: David Woodhouse <dwmw@amazon.co.uk> Date: Sat, 4 Feb 2023 15:20:24 +0000 Subject: [PATCH] parallel debug --- arch/x86/kernel/head_64.S | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 0e4e53d231db..da7f4d2d9951 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -281,6 +281,15 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) .Lsetup_AP: /* EDX contains the APIC ID of the current CPU */ +#if 1 + /* Test hack: Print APIC ID and then CPU# when we find it. */ + mov %edx, %ecx + mov %edx, %eax + addb $'A', %al + mov $0x3f8, %dx + outb %al, %dx + mov %ecx, %edx +#endif xorq %rcx, %rcx leaq cpuid_to_apicid(%rip), %rbx @@ -302,6 +311,14 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) .Linit_cpu_data: /* Get the per cpu offset for the given CPU# which is in ECX */ +#if 1 + mov %rcx, %rax + shr $3, %rax + addb $'a', %al + + mov $0x3f8, %dx + outb %al, %dx +#endif leaq __per_cpu_offset(%rip), %rbx movq (%rbx,%rcx,8), %rbx /* Save it for GS BASE setup */
On 21.02.2023 09:17, David Woodhouse wrote: > On Tue, 2023-02-21 at 09:05 +0100, Oleksandr Natalenko wrote: >> >> Please see here: http://ix.io/4oLm > > Was that just for one CPU? Can we have them all please? > > The interesting part is the line starting 00000001. We're looking at > the top 8 bits of EBX: > > Leaf Subleaf EAX EBX ECX EDX > 00000000 00000000: 00000010 .... 68747541 Auth 444d4163 cAMD > 69746e65 enti > 00000001 00000000: 00a20f12 .... 00200800 .. . 7ef8320b .2.~ > 178bfbff .... > ↑↑ > > So the first CPU is CPU0. Could have told you that... what about the > others? :) Right, sorry. Here it is: http://ix.io/4oLq > If anyone can reproduce this with a serial port, can you try this? > > From 98ad11d0fb88f081f49f7b1496420dbfbeff8833 Mon Sep 17 00:00:00 2001 > From: David Woodhouse <dwmw@amazon.co.uk> > Date: Sat, 4 Feb 2023 15:20:24 +0000 > Subject: [PATCH] parallel debug > > --- > arch/x86/kernel/head_64.S | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > > diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S > index 0e4e53d231db..da7f4d2d9951 100644 > --- a/arch/x86/kernel/head_64.S > +++ b/arch/x86/kernel/head_64.S > @@ -281,6 +281,15 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, > SYM_L_GLOBAL) > > .Lsetup_AP: > /* EDX contains the APIC ID of the current CPU */ > +#if 1 > + /* Test hack: Print APIC ID and then CPU# when we find it. */ > + mov %edx, %ecx > + mov %edx, %eax > + addb $'A', %al > + mov $0x3f8, %dx > + outb %al, %dx > + mov %ecx, %edx > +#endif > xorq %rcx, %rcx > leaq cpuid_to_apicid(%rip), %rbx > > @@ -302,6 +311,14 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, > SYM_L_GLOBAL) > > .Linit_cpu_data: > /* Get the per cpu offset for the given CPU# which is in ECX */ > +#if 1 > + mov %rcx, %rax > + shr $3, %rax > + addb $'a', %al > + > + mov $0x3f8, %dx > + outb %al, %dx > +#endif > leaq __per_cpu_offset(%rip), %rbx > movq (%rbx,%rcx,8), %rbx > /* Save it for GS BASE setup */
On Tue, 2023-02-21 at 09:25 +0100, Oleksandr Natalenko wrote: > > > Right, sorry. Here it is: http://ix.io/4oLq $ echo `grep ^00000001 4oLq | cut -c36-37` 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 01 03 05 07 09 0b 0d 0f 11 13 15 17 19 1b 1d 1f Well they look sane enough. All even APIC IDs and then all the odd ones is a topology that isn't massively surprising. Does it match what you get *before* suspend/resume? Obviously we could stick our fingers in our ears and go "la la la" and just disable it for non-X2APIC, for AMD without X2APIC, or perhaps disable it on *resume* but still use it at boot. But I'd really like to understand what's going on and not do voodoo. Thanks for helping!
On 21.02.2023 09:35, David Woodhouse wrote: > On Tue, 2023-02-21 at 09:25 +0100, Oleksandr Natalenko wrote: >> >> >> Right, sorry. Here it is: http://ix.io/4oLq > > $ echo `grep ^00000001 4oLq | cut -c36-37` > 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 01 03 05 07 09 0b 0d 0f > 11 13 15 17 19 1b 1d 1f > > Well they look sane enough. All even APIC IDs and then all the odd ones > is a topology that isn't massively surprising. > > Does it match what you get *before* suspend/resume? Yes, the output is completely the same after a fresh boot and after a suspend/resume cycle. > Obviously we could stick our fingers in our ears and go "la la la" and > just disable it for non-X2APIC, for AMD without X2APIC, or perhaps > disable it on *resume* but still use it at boot. But I'd really like to > understand what's going on and not do voodoo. Thanks for helping!
On Tue, 2023-02-21 at 09:44 +0100, Oleksandr Natalenko wrote: > On 21.02.2023 09:35, David Woodhouse wrote: > > On Tue, 2023-02-21 at 09:25 +0100, Oleksandr Natalenko wrote: > > > > > > > > > Right, sorry. Here it is: http://ix.io/4oLq > > > > $ echo `grep ^00000001 4oLq | cut -c36-37` > > 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 01 03 05 07 09 0b 0d 0f > > 11 13 15 17 19 1b 1d 1f > > > > Well they look sane enough. All even APIC IDs and then all the odd ones > > is a topology that isn't massively surprising. > > > > Does it match what you get *before* suspend/resume? > > Yes, the output is completely the same after a fresh boot and after a > suspend/resume cycle. > > > Obviously we could stick our fingers in our ears and go "la la la" and > > just disable it for non-X2APIC, for AMD without X2APIC, or perhaps > > disable it on *resume* but still use it at boot. But I'd really like to > > understand what's going on and not do voodoo. Thanks for helping! > Hm... Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set initial_gs = per_cpu_offset(smp_processor_id()) ? Would it not be CPU#0 that comes back up, and should it not get per_cpu_offset(0) ? Or maybe we should just set up smpboot_control for the CPU to find its own stuff, *even* on waking. Since the structures are already set up, it isn't like a clean boot. If you let it boot in parallel mode, what if you just *remove* the line that sets smpboot_control=0 ?
On 21.02.2023 10:06, David Woodhouse wrote: > Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set > > initial_gs = per_cpu_offset(smp_processor_id()) ? > > Would it not be CPU#0 that comes back up, and should it not get > per_cpu_offset(0) ? Wanna me try `initial_gs = per_cpu_offset(0);` too? > Or maybe we should just set up smpboot_control for the CPU to find its > own stuff, *even* on waking. Since the structures are already set up, > it isn't like a clean boot. > > If you let it boot in parallel mode, what if you just *remove* the line > that sets smpboot_control=0 ? If the `smpboot_control = 0;` line in arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() is commented out, and the system is booted in parallel mode, then suspend/resume works.
On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >On 21.02.2023 10:06, David Woodhouse wrote: >> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set >> >> initial_gs = per_cpu_offset(smp_processor_id()) ? >> >> Would it not be CPU#0 that comes back up, and should it not get >> per_cpu_offset(0) ? > >Wanna me try `initial_gs = per_cpu_offset(0);` too? Hm, yes please. There's another one to make zero on the next line up, I think? >> Or maybe we should just set up smpboot_control for the CPU to find its >> own stuff, *even* on waking. Since the structures are already set up, >> it isn't like a clean boot. >> >> If you let it boot in parallel mode, what if you just *remove* the line >> that sets smpboot_control=0 ? > >If the `smpboot_control = 0;` line in arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() is commented out, and the system is booted in parallel mode, then suspend/resume works. Well that's entertaining. Now, can we come up with any theory which doesn't leave us wondering why it ever worked in the first place...?
On 21/02/2023 10:27, David Woodhouse wrote: > > > On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >> On 21.02.2023 10:06, David Woodhouse wrote: >>> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set >>> >>> initial_gs = per_cpu_offset(smp_processor_id()) ? >>> >>> Would it not be CPU#0 that comes back up, and should it not get >>> per_cpu_offset(0) ? >> >> Wanna me try `initial_gs = per_cpu_offset(0);` too? > I think it might be smp_processor_id() and not 0 incase CPU0 was offline at the point the system was suspended? > Hm, yes please. There's another one to make zero on the next line up, I think? > >>> Or maybe we should just set up smpboot_control for the CPU to find its >>> own stuff, *even* on waking. Since the structures are already set up, >>> it isn't like a clean boot. >>> >>> If you let it boot in parallel mode, what if you just *remove* the line >>> that sets smpboot_control=0 ? >> >> If the `smpboot_control = 0;` line in arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() is commented out, and the system is booted in parallel mode, then suspend/resume works. > > Well that's entertaining. Now, can we come up with any theory which doesn't leave us wondering why it ever worked in the first place...?
On 21.02.2023 11:47, Usama Arif wrote: > On 21/02/2023 10:27, David Woodhouse wrote: >> >> On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko >> <oleksandr@natalenko.name> wrote: >>> On 21.02.2023 10:06, David Woodhouse wrote: >>>> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() >>>> set >>>> >>>> initial_gs = per_cpu_offset(smp_processor_id()) ? >>>> >>>> Would it not be CPU#0 that comes back up, and should it not get >>>> per_cpu_offset(0) ? >>> >>> Wanna me try `initial_gs = per_cpu_offset(0);` too? >> > > I think it might be smp_processor_id() and not 0 incase CPU0 was > offline at the point the system was suspended? Is it even possible for CPU 0 to be offline, at least on x86?
On 21.02.2023 11:27, David Woodhouse wrote: > On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko > <oleksandr@natalenko.name> wrote: >> On 21.02.2023 10:06, David Woodhouse wrote: >>> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() >>> set >>> >>> initial_gs = per_cpu_offset(smp_processor_id()) ? >>> >>> Would it not be CPU#0 that comes back up, and should it not get >>> per_cpu_offset(0) ? >> >> Wanna me try `initial_gs = per_cpu_offset(0);` too? > > Hm, yes please. There's another one to make zero on the next line up, I > think? So, ``` early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); initial_gs = per_cpu_offset(0); ``` ? Should I leave `smpboot_control = 0;` commented out, or I should uncomment it back?
On 21 February 2023 11:46:04 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >On 21.02.2023 11:27, David Woodhouse wrote: >> On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko <oleksandr@natalenko.name> wrote: >>> On 21.02.2023 10:06, David Woodhouse wrote: >>>> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set >>>> >>>> initial_gs = per_cpu_offset(smp_processor_id()) ? >>>> >>>> Would it not be CPU#0 that comes back up, and should it not get >>>> per_cpu_offset(0) ? >>> >>> Wanna me try `initial_gs = per_cpu_offset(0);` too? >> >> Hm, yes please. There's another one to make zero on the next line up, I think? > >So, > >``` >early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); >initial_gs = per_cpu_offset(0); >``` > >? > >Should I leave `smpboot_control = 0;` commented out, or I should uncomment it back? Put it back, else those things don't matter. Thanks.
On 21/02/2023 11:42, Oleksandr Natalenko wrote: > On 21.02.2023 11:47, Usama Arif wrote: >> On 21/02/2023 10:27, David Woodhouse wrote: >>> >>> On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko >>> <oleksandr@natalenko.name> wrote: >>>> On 21.02.2023 10:06, David Woodhouse wrote: >>>>> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set >>>>> >>>>> initial_gs = per_cpu_offset(smp_processor_id()) ? >>>>> >>>>> Would it not be CPU#0 that comes back up, and should it not get >>>>> per_cpu_offset(0) ? >>>> >>>> Wanna me try `initial_gs = per_cpu_offset(0);` too? >>> >> >> I think it might be smp_processor_id() and not 0 incase CPU0 was >> offline at the point the system was suspended? > > Is it even possible for CPU 0 to be offline, at least on x86? > It is possible on x86 (using BOOTPARAM_HOTPLUG_CPU0), but I just read the Kconfig option and it says: "resume from hibernate or suspend always starts from CPU0. So hibernate and suspend are prevented if CPU0 is offline." so I guess switching to 0 should be ok.
On 21.02.2023 12:49, David Woodhouse wrote: > On 21 February 2023 11:46:04 GMT, Oleksandr Natalenko > <oleksandr@natalenko.name> wrote: >> On 21.02.2023 11:27, David Woodhouse wrote: >>> On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko >>> <oleksandr@natalenko.name> wrote: >>>> On 21.02.2023 10:06, David Woodhouse wrote: >>>>> Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() >>>>> set >>>>> >>>>> initial_gs = per_cpu_offset(smp_processor_id()) ? >>>>> >>>>> Would it not be CPU#0 that comes back up, and should it not get >>>>> per_cpu_offset(0) ? >>>> >>>> Wanna me try `initial_gs = per_cpu_offset(0);` too? >>> >>> Hm, yes please. There's another one to make zero on the next line up, >>> I think? >> >> So, >> >> ``` >> early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); >> initial_gs = per_cpu_offset(0); >> ``` >> >> ? >> >> Should I leave `smpboot_control = 0;` commented out, or I should >> uncomment it back? > > Put it back, else those things don't matter. Thanks. With this in place: ``` early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); initial_gs = per_cpu_offset(0); smpboot_control = 0; ``` the resume does not work.
On Tue, 2023-02-21 at 11:54 +0000, Usama Arif wrote: > > > On 21/02/2023 11:42, Oleksandr Natalenko wrote: > > On 21.02.2023 11:47, Usama Arif wrote: > > > On 21/02/2023 10:27, David Woodhouse wrote: > > > > > > > > On 21 February 2023 09:49:51 GMT, Oleksandr Natalenko > > > > <oleksandr@natalenko.name> wrote: > > > > > On 21.02.2023 10:06, David Woodhouse wrote: > > > > > > Why does arch/x86/kernel/acpi/sleep.c::x86_acpi_suspend_lowlevel() set > > > > > > > > > > > > initial_gs = per_cpu_offset(smp_processor_id()) ? > > > > > > > > > > > > Would it not be CPU#0 that comes back up, and should it not get > > > > > > per_cpu_offset(0) ? > > > > > > > > > > Wanna me try `initial_gs = per_cpu_offset(0);` too? > > > > > > > > > > I think it might be smp_processor_id() and not 0 incase CPU0 was > > > offline at the point the system was suspended? > > > > Is it even possible for CPU 0 to be offline, at least on x86? > > > > It is possible on x86 (using BOOTPARAM_HOTPLUG_CPU0), but I just read > the Kconfig option and it says: > > "resume from hibernate or suspend always starts from CPU0. > So hibernate and suspend are prevented if CPU0 is offline." > > so I guess switching to 0 should be ok. The interesting question is who ends up using whose stack? Leaving smpboot_control alone (for the parallel case only; we can't just leave it with the APIC ID of the last CPU started in the serial case) will make each CPU find the same CPU# and stack it used to have, from its own APIC ID and the cpuid_to_apicid[] table. I don't really grok what's happening in the non-parallel case. We leave behind the stack for the CPU that happens to be running the suspend function. And then whichever CPU comes back, it'll get *that* stack. I don't understand why the parallel bringup changes this. Does the cpuid to apicid mapping *change* on resume, if the suspending and resuming CPU are different? Do they swap stacks and CPU# somehow?
On Tue, 2023-02-21 at 13:14 +0100, Oleksandr Natalenko wrote: > > With this in place: > > ``` > early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); > initial_gs = per_cpu_offset(0); > smpboot_control = 0; > ``` > > the resume does not work. Yeah, I think it's always running on CPU0 after the other CPUs are taken down anyway. We definitely *do* need to clear smpboot_control because we absolutely want it using the temp_stack we explicitly put into initial_stack, not finding its own idle thread. The problem was that it was never being restored to STARTUP_SECONDARY in the parallel modes, because that's a one-time setup in native_smp_prepare_cpus(). So we can just restore it in arch_thaw_secondary_cpus_begin() too, by working this into patch 6 of the series. (Usama, I think my tree is fairly out of date now so I'll let you do that? Thanks!). diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 50621793671d..3db77a257ae2 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1571,6 +1571,17 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) void arch_thaw_secondary_cpus_begin(void) { + /* + * On suspend, smpboot_control will have been zeroed to allow the + * boot CPU to use explicitly passed values including a temporary + * stack. Since native_smp_prepare_cpus() won't be called again, + * restore the appropriate value for the parallel startup modes. + */ + if (do_parallel_bringup) { + smpboot_control = STARTUP_SECONDARY | + (x2apic_mode ? STARTUP_APICID_CPUID_0B : STARTUP_APICID_CPUID_01); + } + set_cache_aps_delayed_init(true); }
On 21/02/2023 19:10, David Woodhouse wrote: > On Tue, 2023-02-21 at 13:14 +0100, Oleksandr Natalenko wrote: >> >> With this in place: >> >> ``` >> early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); >> initial_gs = per_cpu_offset(0); >> smpboot_control = 0; >> ``` >> >> the resume does not work. > > Yeah, I think it's always running on CPU0 after the other CPUs are > taken down anyway. > > We definitely *do* need to clear smpboot_control because we absolutely > want it using the temp_stack we explicitly put into initial_stack, not > finding its own idle thread. > > The problem was that it was never being restored to STARTUP_SECONDARY > in the parallel modes, because that's a one-time setup in > native_smp_prepare_cpus(). So we can just restore it in > arch_thaw_secondary_cpus_begin() too, by working this into patch 6 of > the series. > > (Usama, I think my tree is fairly out of date now so I'll let you do > that? Thanks!). >Sounds good! Will send out the next revision with below diff, checkpatch fixes and rebased to 6.2 (testing it now). The below fix looks good! Oleksandr, would you mind testing out suspend/resume with the below diff on your AMD machine just to make sure it fixes the issue before I send out the next revision with it. Thanks! > diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c > index 50621793671d..3db77a257ae2 100644 > --- a/arch/x86/kernel/smpboot.c > +++ b/arch/x86/kernel/smpboot.c > @@ -1571,6 +1571,17 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) > > void arch_thaw_secondary_cpus_begin(void) > { > + /* > + * On suspend, smpboot_control will have been zeroed to allow the > + * boot CPU to use explicitly passed values including a temporary > + * stack. Since native_smp_prepare_cpus() won't be called again, > + * restore the appropriate value for the parallel startup modes. > + */ > + if (do_parallel_bringup) { > + smpboot_control = STARTUP_SECONDARY | > + (x2apic_mode ? STARTUP_APICID_CPUID_0B : STARTUP_APICID_CPUID_01); > + } > + > set_cache_aps_delayed_init(true); > } > >
On 21.02.2023 21:04, Usama Arif wrote: > On 21/02/2023 19:10, David Woodhouse wrote: >> On Tue, 2023-02-21 at 13:14 +0100, Oleksandr Natalenko wrote: >>> >>> With this in place: >>> >>> ``` >>> early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0); >>> initial_gs = per_cpu_offset(0); >>> smpboot_control = 0; >>> ``` >>> >>> the resume does not work. >> >> Yeah, I think it's always running on CPU0 after the other CPUs are >> taken down anyway. >> >> We definitely *do* need to clear smpboot_control because we absolutely >> want it using the temp_stack we explicitly put into initial_stack, not >> finding its own idle thread. >> >> The problem was that it was never being restored to STARTUP_SECONDARY >> in the parallel modes, because that's a one-time setup in >> native_smp_prepare_cpus(). So we can just restore it in >> arch_thaw_secondary_cpus_begin() too, by working this into patch 6 of >> the series. >> >> (Usama, I think my tree is fairly out of date now so I'll let you do >> that? Thanks!). > > Sounds good! Will send out the next revision with below diff, > checkpatch > fixes and rebased to 6.2 (testing it now). The below fix looks good! > Oleksandr, would you mind testing out suspend/resume with the below > diff on your AMD machine just to make sure it fixes the issue before I > send out the next revision with it. Thanks! Right, so I applied the whole series + this fix, and the suspend/resume works. Thanks! Reported-by: Oleksandr Natalenko <oleksandr@natalenko.name> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name> There's another open question pending though: why would this series cause booting up one CPU only on an older AMD CPU. But I'd expect Piotr's fellow to chime in occasionally. >> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c >> index 50621793671d..3db77a257ae2 100644 >> --- a/arch/x86/kernel/smpboot.c >> +++ b/arch/x86/kernel/smpboot.c >> @@ -1571,6 +1571,17 @@ void __init native_smp_prepare_cpus(unsigned >> int max_cpus) >> void arch_thaw_secondary_cpus_begin(void) >> { >> + /* >> + * On suspend, smpboot_control will have been zeroed to allow the >> + * boot CPU to use explicitly passed values including a temporary >> + * stack. Since native_smp_prepare_cpus() won't be called again, >> + * restore the appropriate value for the parallel startup modes. >> + */ >> + if (do_parallel_bringup) { >> + smpboot_control = STARTUP_SECONDARY | >> + (x2apic_mode ? STARTUP_APICID_CPUID_0B : STARTUP_APICID_CPUID_01); >> + } >> + >> set_cache_aps_delayed_init(true); >> } >>
David! On Tue, Feb 21 2023 at 19:10, David Woodhouse wrote: > On Tue, 2023-02-21 at 13:14 +0100, Oleksandr Natalenko wrote: > (Usama, I think my tree is fairly out of date now so I'll let you do > that? Thanks!). > > diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c > index 50621793671d..3db77a257ae2 100644 > --- a/arch/x86/kernel/smpboot.c > +++ b/arch/x86/kernel/smpboot.c > @@ -1571,6 +1571,17 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) > > void arch_thaw_secondary_cpus_begin(void) > { > + /* > + * On suspend, smpboot_control will have been zeroed to allow the > + * boot CPU to use explicitly passed values including a temporary > + * stack. Since native_smp_prepare_cpus() won't be called again, > + * restore the appropriate value for the parallel startup modes. > + */ > + if (do_parallel_bringup) { > + smpboot_control = STARTUP_SECONDARY | > + (x2apic_mode ? STARTUP_APICID_CPUID_0B : STARTUP_APICID_CPUID_01); > + } My bad taste sensor reports: "Out of effective range" Why on earth can't you fix the wreckage exactly where it happens, i.e. in x86_acpi_suspend_lowlevel() ? --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -16,6 +16,7 @@ #include <asm/cacheflush.h> #include <asm/realmode.h> #include <asm/hypervisor.h> +#include <asm/smp.h> #include <linux/ftrace.h> #include "../../realmode/rm/wakeup.h" @@ -57,6 +58,7 @@ asmlinkage acpi_status __visible x86_acp */ int x86_acpi_suspend_lowlevel(void) { + unsigned int __maybe_unused saved_smpboot_ctrl; struct wakeup_header *header = (struct wakeup_header *) __va(real_mode_header->wakeup_header); @@ -115,7 +117,8 @@ int x86_acpi_suspend_lowlevel(void) early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(smp_processor_id()); initial_gs = per_cpu_offset(smp_processor_id()); - smpboot_control = 0; + /* Force the startup into boot mode */ + saved_smpboot_ctrl = xchg(&smpboot_control, 0); #endif initial_code = (unsigned long)wakeup_long64; saved_magic = 0x123456789abcdef0L; @@ -128,6 +131,9 @@ int x86_acpi_suspend_lowlevel(void) pause_graph_tracing(); do_suspend_lowlevel(); unpause_graph_tracing(); + + if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_SMP)) + smpboot_control = saved_smpboot_ctrl; return 0; } That's too bloody obvious, too self explaining, not enough duplicated code and does not need any fixups when the smpboot_control bits are changed later, right? Thanks, tglx
On 21 February 2023 21:41:32 GMT, Thomas Gleixner <tglx@linutronix.de> wrote: >David! > >On Tue, Feb 21 2023 at 19:10, David Woodhouse wrote: >> On Tue, 2023-02-21 at 13:14 +0100, Oleksandr Natalenko wrote: >> (Usama, I think my tree is fairly out of date now so I'll let you do >> that? Thanks!). >> >> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c >> index 50621793671d..3db77a257ae2 100644 >> --- a/arch/x86/kernel/smpboot.c >> +++ b/arch/x86/kernel/smpboot.c >> @@ -1571,6 +1571,17 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) >> >> void arch_thaw_secondary_cpus_begin(void) >> { >> + /* >> + * On suspend, smpboot_control will have been zeroed to allow the >> + * boot CPU to use explicitly passed values including a temporary >> + * stack. Since native_smp_prepare_cpus() won't be called again, >> + * restore the appropriate value for the parallel startup modes. >> + */ >> + if (do_parallel_bringup) { >> + smpboot_control = STARTUP_SECONDARY | >> + (x2apic_mode ? STARTUP_APICID_CPUID_0B : STARTUP_APICID_CPUID_01); >> + } > >My bad taste sensor reports: "Out of effective range" > >Why on earth can't you fix the wreckage exactly where it happens, >i.e. in x86_acpi_suspend_lowlevel() ? Er, that was my first instinct but for some reason I concluded that I couldn't put it back there, and it has to be done later because this was just a function called on the way down to suspend. Wrongly, it seems. :) >--- a/arch/x86/kernel/acpi/sleep.c >+++ b/arch/x86/kernel/acpi/sleep.c >@@ -16,6 +16,7 @@ > #include <asm/cacheflush.h> > #include <asm/realmode.h> > #include <asm/hypervisor.h> >+#include <asm/smp.h> > > #include <linux/ftrace.h> > #include "../../realmode/rm/wakeup.h" >@@ -57,6 +58,7 @@ asmlinkage acpi_status __visible x86_acp > */ > int x86_acpi_suspend_lowlevel(void) > { >+ unsigned int __maybe_unused saved_smpboot_ctrl; > struct wakeup_header *header = > (struct wakeup_header *) __va(real_mode_header->wakeup_header); > >@@ -115,7 +117,8 @@ int x86_acpi_suspend_lowlevel(void) > early_gdt_descr.address = > (unsigned long)get_cpu_gdt_rw(smp_processor_id()); > initial_gs = per_cpu_offset(smp_processor_id()); >- smpboot_control = 0; >+ /* Force the startup into boot mode */ >+ saved_smpboot_ctrl = xchg(&smpboot_control, 0); > #endif > initial_code = (unsigned long)wakeup_long64; > saved_magic = 0x123456789abcdef0L; >@@ -128,6 +131,9 @@ int x86_acpi_suspend_lowlevel(void) > pause_graph_tracing(); > do_suspend_lowlevel(); > unpause_graph_tracing(); >+ >+ if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_SMP)) >+ smpboot_control = saved_smpboot_ctrl; > return 0; > } > > >That's too bloody obvious, too self explaining, not enough duplicated >code and does not need any fixups when the smpboot_control bits are >changed later, right? > >Thanks, > > tglx
On Tue, 2023-02-21 at 22:41 +0100, Thomas Gleixner wrote: > > @@ -57,6 +58,7 @@ asmlinkage acpi_status __visible x86_acp > */ > int x86_acpi_suspend_lowlevel(void) > { > + unsigned int __maybe_unused saved_smpboot_ctrl; > struct wakeup_header *header = > (struct wakeup_header *) __va(real_mode_header->wakeup_header); > > @@ -115,7 +117,8 @@ int x86_acpi_suspend_lowlevel(void) > early_gdt_descr.address = > (unsigned long)get_cpu_gdt_rw(smp_processor_id()); > initial_gs = per_cpu_offset(smp_processor_id()); > - smpboot_control = 0; > + /* Force the startup into boot mode */ > + saved_smpboot_ctrl = xchg(&smpboot_control, 0); > #endif > initial_code = (unsigned long)wakeup_long64; > saved_magic = 0x123456789abcdef0L; > @@ -128,6 +131,9 @@ int x86_acpi_suspend_lowlevel(void) > pause_graph_tracing(); > do_suspend_lowlevel(); > unpause_graph_tracing(); > + > + if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_SMP)) > + smpboot_control = saved_smpboot_ctrl; > return 0; > } > But wait, why is this giving it a dedicated temp_stack anyway? Why can't it use that CPU's idle thread stack like we usually do? I already made idle_thread_get() accessible from here. So we could do this... @@ -111,14 +112,16 @@ int x86_acpi_suspend_lowlevel(void) saved_magic = 0x12345678; #else /* CONFIG_64BIT */ #ifdef CONFIG_SMP - initial_stack = (unsigned long)temp_stack + sizeof(temp_stack); - early_gdt_descr.address = - (unsigned long)get_cpu_gdt_rw(smp_processor_id()); - initial_gs = per_cpu_offset(smp_processor_id()); - smpboot_control = 0; + if (!(smpboot_control & STARTUP_PARALLEL_MASK)) { + unsigned int cpu = smp_processor_id(); + initial_stack = (unsigned long)idle_thread_get(cpu)->thread.sp; + early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(cpu); + initial_gs = per_cpu_offset(cpu); + smpboot_control = 0; + } #endif initial_code = (unsigned long)wakeup_long64; But that's a whole bunch of pointless, because it can be even further simplified to just let the find its own crap like the secondaries do, except in the 'OMG CPUID won't tell me' case where it has to be told: So how about we just do something more like this. I'd *quite* like to put the actual handling of smpboot_control into a function we call in smpboot.c. and that whole x86_acpi_suspend_lowlevel() function wants all its horrid 64bit/smp ifdefs fixed up (and is there any reason there's a generic part saving CR0 and IA32_MISC_ENABLE right in the middle of some !CONFIG_64BIT parts? I don't see ordering constraints there). But this should work, I think: diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 33c0d5fd8af6..72b9375fec7c 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -208,4 +208,6 @@ extern unsigned int smpboot_control; #define STARTUP_APICID_CPUID_0B 0x40000000 #define STARTUP_APICID_CPUID_01 0x20000000 +#define STARTUP_PARALLEL_MASK 0x60000000 + #endif /* _ASM_X86_SMP_H */ diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 06adf340a0f1..a1343a900caf 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -16,17 +16,14 @@ #include <asm/cacheflush.h> #include <asm/realmode.h> #include <asm/hypervisor.h> - +#include <asm/smp.h> +#include <linux/smpboot.h> #include <linux/ftrace.h> #include "../../realmode/rm/wakeup.h" #include "sleep.h" unsigned long acpi_realmode_flags; -#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) -static char temp_stack[4096]; -#endif - /** * acpi_get_wakeup_address - provide physical address for S3 wakeup * @@ -111,14 +108,11 @@ int x86_acpi_suspend_lowlevel(void) saved_magic = 0x12345678; #else /* CONFIG_64BIT */ #ifdef CONFIG_SMP - initial_stack = (unsigned long)temp_stack + sizeof(temp_stack); - early_gdt_descr.address = - (unsigned long)get_cpu_gdt_rw(smp_processor_id()); - initial_gs = per_cpu_offset(smp_processor_id()); - smpboot_control = 0; + if (!(smpboot_control & STARTUP_PARALLEL_MASK)) + smpboot_control = STARTUP_SECONDARY | cpu_physical_id(smp_processor_id()); #endif initial_code = (unsigned long)wakeup_long64; - saved_magic = 0x123456789abcdef0L; + saved_magic = 0x123456789abcdef0L; #endif /* CONFIG_64BIT */ /*
On 21/02/2023 23:18, David Woodhouse wrote: > On Tue, 2023-02-21 at 22:41 +0100, Thomas Gleixner wrote: >> >> @@ -57,6 +58,7 @@ asmlinkage acpi_status __visible x86_acp >> */ >> int x86_acpi_suspend_lowlevel(void) >> { >> + unsigned int __maybe_unused saved_smpboot_ctrl; >> struct wakeup_header *header = >> (struct wakeup_header *) __va(real_mode_header->wakeup_header); >> >> @@ -115,7 +117,8 @@ int x86_acpi_suspend_lowlevel(void) >> early_gdt_descr.address = >> (unsigned long)get_cpu_gdt_rw(smp_processor_id()); >> initial_gs = per_cpu_offset(smp_processor_id()); >> - smpboot_control = 0; >> + /* Force the startup into boot mode */ >> + saved_smpboot_ctrl = xchg(&smpboot_control, 0); >> #endif >> initial_code = (unsigned long)wakeup_long64; >> saved_magic = 0x123456789abcdef0L; >> @@ -128,6 +131,9 @@ int x86_acpi_suspend_lowlevel(void) >> pause_graph_tracing(); >> do_suspend_lowlevel(); >> unpause_graph_tracing(); >> + >> + if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_SMP)) >> + smpboot_control = saved_smpboot_ctrl; >> return 0; >> } >> > > But wait, why is this giving it a dedicated temp_stack anyway? Why > can't it use that CPU's idle thread stack like we usually do? I already > made idle_thread_get() accessible from here. So we could do this... > > @@ -111,14 +112,16 @@ int x86_acpi_suspend_lowlevel(void) > saved_magic = 0x12345678; > #else /* CONFIG_64BIT */ > #ifdef CONFIG_SMP > - initial_stack = (unsigned long)temp_stack + sizeof(temp_stack); > - early_gdt_descr.address = > - (unsigned long)get_cpu_gdt_rw(smp_processor_id()); > - initial_gs = per_cpu_offset(smp_processor_id()); > - smpboot_control = 0; > + if (!(smpboot_control & STARTUP_PARALLEL_MASK)) { > + unsigned int cpu = smp_processor_id(); > + initial_stack = (unsigned long)idle_thread_get(cpu)->thread.sp; > + early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(cpu); > + initial_gs = per_cpu_offset(cpu); > + smpboot_control = 0; > + } > #endif > initial_code = (unsigned long)wakeup_long64; > > > But that's a whole bunch of pointless, because it can be even further > simplified to just let the find its own crap like the secondaries do, > except in the 'OMG CPUID won't tell me' case where it has to be told: > > So how about we just do something more like this. I'd *quite* like to > put the actual handling of smpboot_control into a function we call in > smpboot.c. and that whole x86_acpi_suspend_lowlevel() function wants > all its horrid 64bit/smp ifdefs fixed up (and is there any reason > there's a generic part saving CR0 and IA32_MISC_ENABLE right in the > middle of some !CONFIG_64BIT parts? I don't see ordering constraints > there). But this should work, I think: > > diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h > index 33c0d5fd8af6..72b9375fec7c 100644 > --- a/arch/x86/include/asm/smp.h > +++ b/arch/x86/include/asm/smp.h > @@ -208,4 +208,6 @@ extern unsigned int smpboot_control; > #define STARTUP_APICID_CPUID_0B 0x40000000 > #define STARTUP_APICID_CPUID_01 0x20000000 > > +#define STARTUP_PARALLEL_MASK 0x60000000 > + Probably could define STARTUP_PARALLEL_MASK as STARTUP_APICID_CPUID_0B | STARTUP_APICID_CPUID_01 instead? otherwise if its a separate bit, it needs to be set in native_smp_prepare_cpus as well for this to work? > #endif /* _ASM_X86_SMP_H */ > diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c > index 06adf340a0f1..a1343a900caf 100644 > --- a/arch/x86/kernel/acpi/sleep.c > +++ b/arch/x86/kernel/acpi/sleep.c > @@ -16,17 +16,14 @@ > #include <asm/cacheflush.h> > #include <asm/realmode.h> > #include <asm/hypervisor.h> > - > +#include <asm/smp.h> > +#include <linux/smpboot.h> > #include <linux/ftrace.h> > #include "../../realmode/rm/wakeup.h" > #include "sleep.h" > > unsigned long acpi_realmode_flags; > > -#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) > -static char temp_stack[4096]; > -#endif > - > /** > * acpi_get_wakeup_address - provide physical address for S3 wakeup > * > @@ -111,14 +108,11 @@ int x86_acpi_suspend_lowlevel(void) > saved_magic = 0x12345678; > #else /* CONFIG_64BIT */ > #ifdef CONFIG_SMP > - initial_stack = (unsigned long)temp_stack + sizeof(temp_stack); > - early_gdt_descr.address = > - (unsigned long)get_cpu_gdt_rw(smp_processor_id()); > - initial_gs = per_cpu_offset(smp_processor_id()); > - smpboot_control = 0; > + if (!(smpboot_control & STARTUP_PARALLEL_MASK)) > + smpboot_control = STARTUP_SECONDARY | cpu_physical_id(smp_processor_id()); > #endif > initial_code = (unsigned long)wakeup_long64; > - saved_magic = 0x123456789abcdef0L; > + saved_magic = 0x123456789abcdef0L; > #endif /* CONFIG_64BIT */ > > /* > >
On Wed, 2023-02-22 at 00:00 +0000, Usama Arif wrote: > > > diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h > > index 33c0d5fd8af6..72b9375fec7c 100644 > > --- a/arch/x86/include/asm/smp.h > > +++ b/arch/x86/include/asm/smp.h > > @@ -208,4 +208,6 @@ extern unsigned int smpboot_control; > > #define STARTUP_APICID_CPUID_0B 0x40000000 > > #define STARTUP_APICID_CPUID_01 0x20000000 > > > > +#define STARTUP_PARALLEL_MASK 0x60000000 > > + > > Probably could define STARTUP_PARALLEL_MASK as STARTUP_APICID_CPUID_0B | > STARTUP_APICID_CPUID_01 instead? otherwise if its a separate bit, it > needs to be set in native_smp_prepare_cpus as well for this to work? It is CPUID_0B | CPUID_01, unless I was being really stupid last night. Sips coffee... yep, 6 = 4 | 2. I could have made that more obvious with a bit more typing, I suppose. However, I don't think this approach is correct. The idle thread stacks for the other CPUs are *unused* because those CPUs are offline. So we can use them with impunity, and when those CPUs come back online they'll call into cpu_startup_entry(CPUHP_AP_ONLINE_IDLE) using the correct stack. But the BSP/CPU0 is different. It hasn't actually been taken offline, and its idle thread context is still in cpu_startup_entry(CPUHP_ONLINE) which got called from rest_init(). In testing I probably got away with it because we're only using the *top* of the stack, don't use anything of the red zone, and thus don't actually bother the true idle thread which is never going to return. But I don't think it's correct; we really ought to have that temp_stack unless we're going to refactor the wakeup_64 code to *become* the idle thread just as startup_secondary() does, and *schedule* to the context that was saved in the suspend code. That might be an interesting cleanup, and let us use the normal __switch_to() to save and restore a bunch of context which is currently done by hand. But not today.
On Tue, Feb 21 2023 at 23:18, David Woodhouse wrote: > On Tue, 2023-02-21 at 22:41 +0100, Thomas Gleixner wrote: >> + >> + if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_SMP)) >> + smpboot_control = saved_smpboot_ctrl; >> return 0; >> } >> > > But wait, why is this giving it a dedicated temp_stack anyway? Why > can't it use that CPU's idle thread stack like we usually do? I already > made idle_thread_get() accessible from here. So we could do this... Because this very CPU is still online and from the kernels POV is does not go offline. It goes into the firmware blackhole and comes back magically through the startup code. That means this very CPUs indle thread stack is in use and the resume path will scribble over it. Maybe you won't notice because it only clobbers top of stack which is never used again because the idle thread does not return. But correct is something different. Thanks, tglx
On Wed, Feb 22 2023 at 08:19, David Woodhouse wrote: > But the BSP/CPU0 is different. It hasn't actually been taken offline, > and its idle thread context is still in cpu_startup_entry(CPUHP_ONLINE) > which got called from rest_init(). > > In testing I probably got away with it because we're only using the > *top* of the stack, don't use anything of the red zone, and thus don't > actually bother the true idle thread which is never going to return. :) > But I don't think it's correct; we really ought to have that temp_stack > unless we're going to refactor the wakeup_64 code to *become* the idle > thread just as startup_secondary() does, and *schedule* to the context > that was saved in the suspend code. And thereby messing up the scheduler state... Thanks, tglx
On Wed, 2023-02-22 at 10:46 +0100, Thomas Gleixner wrote: > On Wed, Feb 22 2023 at 08:19, David Woodhouse wrote: > > But the BSP/CPU0 is different. It hasn't actually been taken offline, > > and its idle thread context is still in cpu_startup_entry(CPUHP_ONLINE) > > which got called from rest_init(). > > > > In testing I probably got away with it because we're only using the > > *top* of the stack, don't use anything of the red zone, and thus don't > > actually bother the true idle thread which is never going to return. > > :) > > > But I don't think it's correct; we really ought to have that temp_stack > > unless we're going to refactor the wakeup_64 code to *become* the idle > > thread just as startup_secondary() does, and *schedule* to the context > > that was saved in the suspend code. > > And thereby messing up the scheduler state... Indeed. Which is probably fixable but also probably more of a wart in the scheduler code, than it's worth for the negligible cleanup in the suspend code. Hence "not today". Which is code for "not ever". But don't tell my children that.
On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: > The main change over v8 is dropping the patch to avoid repeated saves of MTRR > at boot time. It didn't make a difference to smpboot time and is independent > of parallel CPU bringup, so if needed can be explored in a separate patchset. > > The patches have also been rebased to v6.2-rc8 and retested and the > improvement in boot time is the same as v8. Thanks for picking this up, Usama. So the next thing that might be worth looking at is allowing the APs all to be running their hotplug thread simultaneously, bringing themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats the initial INIT/SIPI/SIPI latency, but if there's any significant time in the AP hotplug thread, that could be worth parallelising. There may be further wins in the INIT/SIPI/SIPI too. Currently we process each CPU at a time, sending INIT, SIPI, waiting 10µs and sending another SIPI. What if we sent the first INIT+SIPI to all CPUs, then did another pass sending another SIPI only to those which hadn't already started running and set their bit in cpu_initialized_mask ? Might not be worth it, and there's an added complexity that they all have to wait for each other (on the real mode trampoline lock) before they can take their turn and get as far as setting their bit in cpu_initialized_mask. So we'd probably end up sending the second SIPI to most of them *anyway*.
On 22/02/2023 10:11, David Woodhouse wrote: > On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: >> The main change over v8 is dropping the patch to avoid repeated saves of MTRR >> at boot time. It didn't make a difference to smpboot time and is independent >> of parallel CPU bringup, so if needed can be explored in a separate patchset. >> >> The patches have also been rebased to v6.2-rc8 and retested and the >> improvement in boot time is the same as v8. > > Thanks for picking this up, Usama. > > So the next thing that might be worth looking at is allowing the APs > all to be running their hotplug thread simultaneously, bringing > themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats > the initial INIT/SIPI/SIPI latency, but if there's any significant time > in the AP hotplug thread, that could be worth parallelising. > > There may be further wins in the INIT/SIPI/SIPI too. Currently we > process each CPU at a time, sending INIT, SIPI, waiting 10µs and > sending another SIPI. > > What if we sent the first INIT+SIPI to all CPUs, then did another pass > sending another SIPI only to those which hadn't already started running > and set their bit in cpu_initialized_mask ? > > Might not be worth it, and there's an added complexity that they all > have to wait for each other (on the real mode trampoline lock) before > they can take their turn and get as far as setting their bit in > cpu_initialized_mask. So we'd probably end up sending the second SIPI > to most of them *anyway*. Thanks! I think I sent out v10 a bit too early, but hopefully it looks like everyone agrees on the suspend code in it at the moment? As a next step, I was thinking of reposting and starting a discussion on the reuse timer calibration patch separately. Its not part of parallel smp, but in my testing, it takes away (70ms) ~70% of the remaining parallel smpboot time. With the machine and kernel I am testing, the kexec reboot time after parallel smp is just under a second, so this represents ~7% of the boot time, which is a notable percentage reduction in server downtime. Or maybe someone could reply to this thread saying its not a good idea to post it as I remember there were quite a few reservations about it? :) Thanks, Usama
On Wed, Feb 22, 2023 at 5:44 AM David Woodhouse <dwmw2@infradead.org> wrote: > > On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: > > The main change over v8 is dropping the patch to avoid repeated saves of MTRR > > at boot time. It didn't make a difference to smpboot time and is independent > > of parallel CPU bringup, so if needed can be explored in a separate patchset. > > > > The patches have also been rebased to v6.2-rc8 and retested and the > > improvement in boot time is the same as v8. > > Thanks for picking this up, Usama. > > So the next thing that might be worth looking at is allowing the APs > all to be running their hotplug thread simultaneously, bringing > themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats > the initial INIT/SIPI/SIPI latency, but if there's any significant time > in the AP hotplug thread, that could be worth parallelising. > > There may be further wins in the INIT/SIPI/SIPI too. Currently we > process each CPU at a time, sending INIT, SIPI, waiting 10µs and > sending another SIPI. > > What if we sent the first INIT+SIPI to all CPUs, then did another pass > sending another SIPI only to those which hadn't already started running > and set their bit in cpu_initialized_mask ? > > Might not be worth it, and there's an added complexity that they all > have to wait for each other (on the real mode trampoline lock) before > they can take their turn and get as far as setting their bit in > cpu_initialized_mask. So we'd probably end up sending the second SIPI > to most of them *anyway*. Speaking of next steps, I have a followup patchset ready to go that removes the global variables initial_stack, initial_gs, and early_gdt_descr. Should I send that now or wait until this patchset lands in -tip? -- Brian Gerst
On 22 February 2023 12:08:04 GMT, Brian Gerst <brgerst@gmail.com> wrote: >On Wed, Feb 22, 2023 at 5:44 AM David Woodhouse <dwmw2@infradead.org> wrote: >> >> On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: >> > The main change over v8 is dropping the patch to avoid repeated saves of MTRR >> > at boot time. It didn't make a difference to smpboot time and is independent >> > of parallel CPU bringup, so if needed can be explored in a separate patchset. >> > >> > The patches have also been rebased to v6.2-rc8 and retested and the >> > improvement in boot time is the same as v8. >> >> Thanks for picking this up, Usama. >> >> So the next thing that might be worth looking at is allowing the APs >> all to be running their hotplug thread simultaneously, bringing >> themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats >> the initial INIT/SIPI/SIPI latency, but if there's any significant time >> in the AP hotplug thread, that could be worth parallelising. >> >> There may be further wins in the INIT/SIPI/SIPI too. Currently we >> process each CPU at a time, sending INIT, SIPI, waiting 10µs and >> sending another SIPI. >> >> What if we sent the first INIT+SIPI to all CPUs, then did another pass >> sending another SIPI only to those which hadn't already started running >> and set their bit in cpu_initialized_mask ? >> >> Might not be worth it, and there's an added complexity that they all >> have to wait for each other (on the real mode trampoline lock) before >> they can take their turn and get as far as setting their bit in >> cpu_initialized_mask. So we'd probably end up sending the second SIPI >> to most of them *anyway*. > >Speaking of next steps, I have a followup patchset ready to go that >removes the global variables initial_stack, initial_gs, and >early_gdt_descr. Should I send that now or wait until this patchset >lands in -tip? Happy either way. Want to send it and we can take a look at whether to work it in with this?
David! On Wed, Feb 22 2023 at 10:11, David Woodhouse wrote: > On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: > So the next thing that might be worth looking at is allowing the APs > all to be running their hotplug thread simultaneously, bringing > themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats > the initial INIT/SIPI/SIPI latency, but if there's any significant time > in the AP hotplug thread, that could be worth parallelising. On a 112 CPU machine (64 cores, HT enabled) the bringup takes Setup and SIPIs sent: 49 ms Bringup each CPU: 516 ms That's about 500 ms faster than a non-parallel bringup! Now looking at the 516 ms, which is ~4.7 ms/CPU. The vast majority of the time is spent on the APs in cpu_init() -> ucode_cpu_init() for the primary threads of each core. The secondary threads are quickly (1us) out of ucode_cpu_init() because the primary thread already loaded it. A microcode load on that machine takes ~7.5 ms per primary thread on average which sums up to 7.5 * 55 = 412.5 ms The threaded bringup after CPU_AP_ONLINE takes about 100us per CPU. identify_secondary_cpu() is one of the longer functions which takes ~125us / CPU summing up to 13ms The TSC sync check for the first CPU on the second socket consumes 20ms. That's only once per socket, intra socket is using MSR_TSC_ADJUST, which is more or less free. So the 516 ms are wasted here: total 516 ms ucode_cpu_init() 412 ms identify_secondary_cpu() 13 ms 2ndsocket_tsc_sync 20 ms threaded bringup 12 ms rest 59 ms So the rest is about 530us per CPU, which is just the sum of many small functions, lock contentions... Getting rid of the micro code overhead is possible. There is no reason to serialize that between the cores. But it needs serialization vs. HT siblings, which requires to move identify_secondary_cpu() and its caller smp_store_cpu_info() ahead of the synchronization point and then have serialization between the siblings. That's going to be a major surgery and inspection effort to ensure that there are no hidden assumptions about global hotplug serialization. So that would cut the total cost down to ~100ms plus the preparatory/SIPI stage of 60ms which sums up to about 160ms and about 1.5ms per CPU total. Further optimization starts to be questionable IMO. It's surely possible somehow, but then you really have to go and inspect each and every function in those code pathes, add local locking, etc. Not to talk about the required mess in the core code to support that. The low hanging fruit which brings most is the identification/topology muck and the microcode loading. That needs to be addressed first anyway. Thanks, tglx
On Wed, 2023-02-22 at 17:42 +0100, Thomas Gleixner wrote: > David! > > On Wed, Feb 22 2023 at 10:11, David Woodhouse wrote: > > On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: > > So the next thing that might be worth looking at is allowing the APs > > all to be running their hotplug thread simultaneously, bringing > > themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats > > the initial INIT/SIPI/SIPI latency, but if there's any significant time > > in the AP hotplug thread, that could be worth parallelising. > > On a 112 CPU machine (64 cores, HT enabled) the bringup takes > > Setup and SIPIs sent: 49 ms > Bringup each CPU: 516 ms > > That's about 500 ms faster than a non-parallel bringup! > > Now looking at the 516 ms, which is ~4.7 ms/CPU. The vast majority of the > time is spent on the APs in > > cpu_init() -> ucode_cpu_init() > > for the primary threads of each core. The secondary threads are quickly > (1us) out of ucode_cpu_init() because the primary thread already loaded > it. > > A microcode load on that machine takes ~7.5 ms per primary thread on > average which sums up to 7.5 * 55 = 412.5 ms > > The threaded bringup after CPU_AP_ONLINE takes about 100us per CPU. Nice analysis; thanks! > identify_secondary_cpu() is one of the longer functions which takes > ~125us / CPU summing up to 13ms Hm, shouldn't that one already be parallelised by my 'part 2' patch? It's called from smp_store_cpu_info(), from smp_callin(), which is called from somewhere in the middle of start_secondary(). And if the comments I helpfully added to that function for the benefit of our future selves are telling the truth, the AP is free to get that far once the BSP has set its bit in cpu_callout_mask, which happens in do_wait_cpu_initialized(). So https://git.infradead.org/users/dwmw2/linux.git/commitdiff/4b5731e05b0#patch3 ought to parallelise that. But Usama emirically reported that 'part 2' didn't add any noticeable benefit, not even those 13ms? On a *larger* machine. > The TSC sync check for the first CPU on the second socket consumes > 20ms. That's only once per socket, intra socket is using MSR_TSC_ADJUST, > which is more or less free. > > So the 516 ms are wasted here: > > total 516 ms > ucode_cpu_init() 412 ms > identify_secondary_cpu() 13 ms > 2ndsocket_tsc_sync 20 ms > threaded bringup 12 ms > rest 59 ms > > So the rest is about 530us per CPU, which is just the sum of many small > functions, lock contentions... > > Getting rid of the micro code overhead is possible. There is no reason > to serialize that between the cores. But it needs serialization vs. HT > siblings, which requires to move identify_secondary_cpu() and its caller > smp_store_cpu_info() ahead of the synchronization point and then have > serialization between the siblings. That's going to be a major surgery > and inspection effort to ensure that there are no hidden assumptions > about global hotplug serialization. > > So that would cut the total cost down to ~100ms plus the > preparatory/SIPI stage of 60ms which sums up to about 160ms and about > 1.5ms per CPU total. > > Further optimization starts to be questionable IMO. It's surely possible > somehow, but then you really have to go and inspect each and every > function in those code pathes, add local locking, etc. Not to talk about > the required mess in the core code to support that. > > The low hanging fruit which brings most is the identification/topology > muck and the microcode loading. That needs to be addressed first anyway. Agreed, thanks.
David! On Thu, Feb 23 2023 at 11:07, David Woodhouse wrote: > On Wed, 2023-02-22 at 17:42 +0100, Thomas Gleixner wrote: >> The low hanging fruit which brings most is the identification/topology >> muck and the microcode loading. That needs to be addressed first anyway. > > Agreed, thanks. So the problem with microcode loading is that we must ensure that a HT sibling is not executing anything else than a trivial loop waiting for the update to complete. So something like this should work: 1) Kick all CPUs into life and let them run up to cpu_init() and retrieve only the topology information. 2) Wait for all CPUs to reach this point 3) Release all primary HT threads so they can load microcode in parallel. The secondary HT threads stay in the wait loop and are released once the primary thread has finished the microcode update. 4) Let the CPUs do the full CPUID readout and let them synchronize with the control CPU again. 5) Complete bringup one by one Thanks, tglx
On Thu, 2023-02-23 at 15:37 +0100, Thomas Gleixner wrote: > David! > > On Thu, Feb 23 2023 at 11:07, David Woodhouse wrote: > > On Wed, 2023-02-22 at 17:42 +0100, Thomas Gleixner wrote: > > > The low hanging fruit which brings most is the identification/topology > > > muck and the microcode loading. That needs to be addressed first anyway. > > > > Agreed, thanks. > > So the problem with microcode loading is that we must ensure that a HT > sibling is not executing anything else than a trivial loop waiting for > the update to complete. So something like this should work: > > 1) Kick all CPUs into life and let them run up to cpu_init() and > retrieve only the topology information. > > 2) Wait for all CPUs to reach this point > > 3) Release all primary HT threads so they can load microcode in > parallel. The secondary HT threads stay in the wait loop and are > released once the primary thread has finished the microcode > update. > > 4) Let the CPUs do the full CPUID readout and let them synchronize > with the control CPU again. > > 5) Complete bringup one by one Can we move the microcode loading to happen earlier, during the x86- specific CPUHP_BP_PARALLEL_DYN stage(s) while they're running in parallel. In the existing set of patches, we send INIT/SIPI/SIPI to each CPU in parallel and they run to the first part of start_secondary(), up to the point where it calls cpu_init_secondary() and sets their bit in cpu_initialized_mask, then spinning and waiting for cpu_callout_mask. My "part 2" test patch does another round in parallel, setting each CPU's bit in 'cpu_callout_mask' and letting them run a bit further through start_secondary() until they get to the end of smp_callin(), where they set their bit in smp_callin_mask and (in my patch) wait for their bit in a new cpu_finishup_mask to be set — which is what releases them to proceed to completion in the final native_cpu_up() bringup. So perhaps the BSP doesn't need to coordinate anything here, if we can let the siblings work it out between themselves in the (now-)parallel stage at the end of smp_callin()? And only set their bit in smp_callin_mask when the microcode update is done? Hm, maybe it's as simple as the first¹ thread on a core waiting for all its siblings' bits in cpu_callin_mask to be set, and *then* doing the update before setting its own bit? ¹ As long as we define "first" as the one with the lowest CPU#, which means that the BSP won't release any of the siblings before it releases the "first". Then the siblings are just spinning on cpu_callin_mask anyway; they don't need to do anything *more*. Probably worth knocking it up and seeing how badly it explodes?
On 23/02/2023 11:07, David Woodhouse wrote: > On Wed, 2023-02-22 at 17:42 +0100, Thomas Gleixner wrote: >> David! >> >> On Wed, Feb 22 2023 at 10:11, David Woodhouse wrote: >>> On Wed, 2023-02-15 at 14:54 +0000, Usama Arif wrote: >>> So the next thing that might be worth looking at is allowing the APs >>> all to be running their hotplug thread simultaneously, bringing >>> themselves from CPUHP_BRINGUP_CPU to CPUHP_AP_ONLINE. This series eats >>> the initial INIT/SIPI/SIPI latency, but if there's any significant time >>> in the AP hotplug thread, that could be worth parallelising. >> >> On a 112 CPU machine (64 cores, HT enabled) the bringup takes >> >> Setup and SIPIs sent: 49 ms >> Bringup each CPU: 516 ms >> >> That's about 500 ms faster than a non-parallel bringup! >> >> Now looking at the 516 ms, which is ~4.7 ms/CPU. The vast majority of the >> time is spent on the APs in >> >> cpu_init() -> ucode_cpu_init() >> >> for the primary threads of each core. The secondary threads are quickly >> (1us) out of ucode_cpu_init() because the primary thread already loaded >> it. >> >> A microcode load on that machine takes ~7.5 ms per primary thread on >> average which sums up to 7.5 * 55 = 412.5 ms >> >> The threaded bringup after CPU_AP_ONLINE takes about 100us per CPU. > > Nice analysis; thanks! > >> identify_secondary_cpu() is one of the longer functions which takes >> ~125us / CPU summing up to 13ms > > Hm, shouldn't that one already be parallelised by my 'part 2' patch? > > It's called from smp_store_cpu_info(), from smp_callin(), which is > called from somewhere in the middle of start_secondary(). > > And if the comments I helpfully added to that function for the benefit > of our future selves are telling the truth, the AP is free to get that > far once the BSP has set its bit in cpu_callout_mask, which happens in > do_wait_cpu_initialized(). > > So > https://git.infradead.org/users/dwmw2/linux.git/commitdiff/4b5731e05b0#patch3 > ought to parallelise that. But Usama emirically reported that 'part 2' > didn't add any noticeable benefit, not even those 13ms? On a *larger* > machine. > So I am using a similar machine to Thomas 128 CPU machine (64 cores, HT enabled). I have microcode config disabled, so I guess I get similar numbers to Thomas, i.e. 100ms (516 - 412) ms. I do see a difference of ~3ms with part2 which I thought is maybe within the margin of error for measuring, but I guess it isn't. After seeing the ~70ms that is cut with reusing timer calibration, I didnt really then focus much on part 2 then. I guess that ~70ms is the "rest" from Thomas' table below? Thanks, Usama > >> The TSC sync check for the first CPU on the second socket consumes >> 20ms. That's only once per socket, intra socket is using MSR_TSC_ADJUST, >> which is more or less free. >> >> So the 516 ms are wasted here: >> >> total 516 ms >> ucode_cpu_init() 412 ms >> identify_secondary_cpu() 13 ms >> 2ndsocket_tsc_sync 20 ms >> threaded bringup 12 ms >> rest 59 ms >> >> So the rest is about 530us per CPU, which is just the sum of many small >> functions, lock contentions... >> >> Getting rid of the micro code overhead is possible. There is no reason >> to serialize that between the cores. But it needs serialization vs. HT >> siblings, which requires to move identify_secondary_cpu() and its caller >> smp_store_cpu_info() ahead of the synchronization point and then have >> serialization between the siblings. That's going to be a major surgery >> and inspection effort to ensure that there are no hidden assumptions >> about global hotplug serialization. >> >> So that would cut the total cost down to ~100ms plus the >> preparatory/SIPI stage of 60ms which sums up to about 160ms and about >> 1.5ms per CPU total. >> >> Further optimization starts to be questionable IMO. It's surely possible >> somehow, but then you really have to go and inspect each and every >> function in those code pathes, add local locking, etc. Not to talk about >> the required mess in the core code to support that. >> >> The low hanging fruit which brings most is the identification/topology >> muck and the microcode loading. That needs to be addressed first anyway. > > Agreed, thanks. >