Skip to contentSkip to conversation

ARM: avoid Cortex-A9 livelock on tight dmb loops

PATCH Superseded Russell King 4 participants 6 messages Jun 1, 2018 – Jun 4, 2018

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 ARM: avoid Cortex-A9 livelock on tight dmb loops

Executing loops such as:

	while (1)
		cpu_relax();

with interrupts disabled results in a livelock of the entire system, as other CPUs are prevented making progress. This is most noticable as a failure of crashdump kexec, which stops just after issuing:

Loading crashdump kernel...

to the system console. Two other locations of these loops within the ARM code have been identified and fixed up.

---
v2: use wfe() instead of cpu_do_idle

 arch/arm/include/asm/barrier.h   | 2 ++
 arch/arm/kernel/machine_kexec.c  | 5 ++++-
 arch/arm/kernel/smp.c            | 4 +++-
 arch/arm/mach-omap2/prm_common.c | 4 +++-
 4 files changed, 12 insertions(+), 3 deletions(-)
arch/arm/include/asm/barrier.h +2 -0
index 69772e742a0a..83ae97c049d9 100644
@@ -11,6 +11,8 @@
 #define sev()	__asm__ __volatile__ ("sev" : : : "memory")
 #define wfe()	__asm__ __volatile__ ("wfe" : : : "memory")
 #define wfi()	__asm__ __volatile__ ("wfi" : : : "memory")
+#else
+#define wfe()	do { } while (0)
 #endif
 
 #if __LINUX_ARM_ARCH__ >= 7
arch/arm/kernel/machine_kexec.c +4 -1
index dd2eb5f76b9f..76300f3813e8 100644
@@ -91,8 +91,11 @@ void machine_crash_nonpanic_core(void *unused)
 
 	set_cpu_online(smp_processor_id(), false);
 	atomic_dec(&waiting_for_crash_ipi);
-	while (1)
+
+	while (1) {
 		cpu_relax();
+		wfe();
+	}
 }
 
 void crash_smp_send_stop(void)
arch/arm/kernel/smp.c +3 -1
index 9ec9a366ef44..a39fe6ab89a2 100644
@@ -570,8 +570,10 @@ static void ipi_cpu_stop(unsigned int cpu)
 	local_fiq_disable();
 	local_irq_disable();
 
-	while (1)
+	while (1) {
 		cpu_relax();
+		wfe();
+	}
 }
 
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
arch/arm/mach-omap2/prm_common.c +3 -1
index 021b5a8b9c0a..bb15a9eec05c 100644
@@ -522,8 +522,10 @@ void omap_prm_reset_system(void)
 
 	prm_ll_data->reset_system();
 
-	while (1)
+	while (1) {
 		cpu_relax();
+		wfe();
+	}
 }
 
 /**
Signature · 1 line
2.7.4
maintainer
#1 lore raw

PATCH v2 1/1 ARM: avoid Cortex-A9 livelock on tight dmb loops

Quoted 9 lines · Russell King

Executing loops such as:

	while (1)
		cpu_relax();

with interrupts disabled results in a livelock of the entire system, as other CPUs are prevented making progress. This is most noticable as a failure of crashdump kexec, which stops just after issuing:

Quoted 6 lines

Loading crashdump kernel...

to the system console. Two other locations of these loops within the ARM code have been identified and fixed up.

Works for me thanks:

BTW, do LZMA crashkernels boot for you with crashdump?

For me LZMA crashkernels fail to boot while GZIP crashkernels boots. Some more info below for failing and working output.

Regards,

Tony

8< ----------------------
CONFIG_KERNEL_LZMA fails:

Try gzip decompression.
Try LZMA decompression.
lzma_decompress_file: read on /boot/zImage of 65536 bytes failed
kernel: 0xb6abb010 kernel_size: 0x43d0f0
MEMORY RANGES
0000000080000000-00000000bfdfffff (0)
zImage header: 0x016f2818 0x00000000 0x0043d0f0
zImage size 0x43d0f0, file size 0x43d0f0
Reserved memory ranges
00000000a8000000-00000000abffffff (0)
Coredump memory ranges
0000000080000000-00000000a7ffffff (0)
00000000ac000000-00000000bfdfffff (0)
kernel symbol _stext vaddr = c0100000
phys offset = 0x80000000, page offset = c0000000
Using 32-bit ELF core format
get_crash_notes_per_cpu: crash_notes addr = be001200, size = 180
Elf header: p_type = 4, p_offset = 0xbe001200 p_paddr = 0xbe001200 p_vaddr = 0x0 p_filesz = 0xb4 p_memsz = 0xb4
get_crash_notes_per_cpu: crash_notes addr = be002200, size = 180
Elf header: p_type = 4, p_offset = 0xbe002200 p_paddr = 0xbe002200 p_vaddr = 0x0 p_filesz = 0xb4 p_memsz = 0xb4 vmcoreinfo header: p_type = 4, p_offset = 0xaeae2000 p_paddr = 0xaeae2000 p_vaddr = 0x0 p_filesz = 0x1024 p_memsz = 0x1024 Elf header: p_type = 1, p_offset = 0x80000000 p_paddr = 0x80000000 p_vaddr = 0xc0000000 p_filesz = 0x28000000 p_memsz = 0x2800 0000
Elf header: p_type = 1, p_offset = 0xac000000 p_paddr = 0xac000000 p_vaddr = 0xec000000 p_filesz = 0x13e00000 p_memsz = 0x13e0 0000
elfcorehdr: 0xabf00000
crashkernel: [0xa8000000 - 0xabffffff] (64M)
memory range: [0x80000000 - 0xa7ffffff] (640M)
memory range: [0xac000000 - 0xbfdfffff] (318M)
kernel command line: "console=ttyS2,115200n8 root=/dev/nfs ip=dhcp debug earlyprintk earlycon crashkernel=64M elfcorehdr=0xabf 00000 mem=64512K"
kexec_load: entry = 0xa8008000 flags = 0x280001
nr_segments = 3
segment[0].buf = 0xb6abb010
segment[0].bufsz = 0x43d0f0
segment[0].mem = 0xa8008000
segment[0].memsz = 0x43e000
segment[1].buf = 0x53dc80
segment[1].bufsz = 0x128da
segment[1].mem = 0xa953b000
segment[1].memsz = 0x13000
segment[2].buf = 0xb6fe8150
segment[2].bufsz = 0x400
segment[2].mem = 0xabf00000
segment[2].memsz = 0x1000

CONFIG_KERNEL_GZIP Works:

Try gzip decompression.
Try LZMA decompression.
lzma_decompress_file: read on /boot/zImage of 65536 bytes failed
kernel: 0xb693f010 kernel_size: 0x5c74a8
MEMORY RANGES
0000000080000000-00000000bfdfffff (0)
zImage header: 0x016f2818 0x00000000 0x005c74a8
zImage size 0x5c74a8, file size 0x5c74a8
Reserved memory ranges
00000000a8000000-00000000abffffff (0)
Coredump memory ranges
0000000080000000-00000000a7ffffff (0)
00000000ac000000-00000000bfdfffff (0)
kernel symbol _stext vaddr = c0100000
phys offset = 0x80000000, page offset = c0000000
Using 32-bit ELF core format
get_crash_notes_per_cpu: crash_notes addr = be001200, size = 180
Elf header: p_type = 4, p_offset = 0xbe001200 p_paddr = 0xbe001200 p_vaddr = 0x0 p_filesz = 0xb4 p_memsz = 0xb4
get_crash_notes_per_cpu: crash_notes addr = be002200, size = 180
Elf header: p_type = 4, p_offset = 0xbe002200 p_paddr = 0xbe002200 p_vaddr = 0x0 p_filesz = 0xb4 p_memsz = 0xb4 vmcoreinfo header: p_type = 4, p_offset = 0xaeae2000 p_paddr = 0xaeae2000 p_vaddr = 0x0 p_filesz = 0x1024 p_memsz = 0x1024 Elf header: p_type = 1, p_offset = 0x80000000 p_paddr = 0x80000000 p_vaddr = 0xc0000000 p_filesz = 0x28000000 p_memsz = 0x28000000 Elf header: p_type = 1, p_offset = 0xac000000 p_paddr = 0xac000000 p_vaddr = 0xec000000 p_filesz = 0x13e00000 p_memsz = 0x13e00000
elfcorehdr: 0xabf00000
crashkernel: [0xa8000000 - 0xabffffff] (64M)
memory range: [0x80000000 - 0xa7ffffff] (640M)
memory range: [0xac000000 - 0xbfdfffff] (318M)
kernel command line: "console=ttyS2,115200n8 root=/dev/nfs ip=dhcp debug earlyprintk earlycon crashkernel=64M elfcorehdr=0xabf00000 mem=64512K"
kexec_load: entry = 0xa8008000 flags = 0x280001
nr_segments = 3
segment[0].buf = 0xb693f010
segment[0].bufsz = 0x5c74a8
segment[0].mem = 0xa8008000
segment[0].memsz = 0x5c8000
segment[1].buf = 0x476c80
segment[1].bufsz = 0x128da
segment[1].mem = 0xa9cee000
segment[1].memsz = 0x13000
segment[2].buf = 0xb6ff6150
segment[2].bufsz = 0x400
segment[2].mem = 0xabf00000
segment[2].memsz = 0x1000

#2 lore raw

PATCH v2 1/1 ARM: avoid Cortex-A9 livelock on tight dmb loops

Quoted 12 lines · Tony Lindgren
Quoted 11 lines · Russell King

Executing loops such as:

	while (1)
		cpu_relax();

with interrupts disabled results in a livelock of the entire system, as other CPUs are prevented making progress. This is most noticable as a failure of crashdump kexec, which stops just after issuing:

Loading crashdump kernel...

Quoted 8 lines
Quoted 4 lines

to the system console. Two other locations of these loops within the ARM code have been identified and fixed up.

Works for me thanks:

Thanks.

Quoted 12 lines

BTW, do LZMA crashkernels boot for you with crashdump?

For me LZMA crashkernels fail to boot while GZIP crashkernels boots. Some more info below for failing and working output.

Regards,

Tony

8< ----------------------
CONFIG_KERNEL_LZMA fails:

Quoted 9 lines

Try gzip decompression.
Try LZMA decompression.
lzma_decompress_file: read on /boot/zImage of 65536 bytes failed
kernel: 0xb6abb010 kernel_size: 0x43d0f0
MEMORY RANGES
0000000080000000-00000000bfdfffff (0)
zImage header: 0x016f2818 0x00000000 0x0043d0f0
zImage size 0x43d0f0, file size 0x43d0f0
Reserved memory ranges

This looks like an old kexec binary as it's missing the output from:

        dbgprintf("zImage requires 0x%08llx bytes\n", (unsigned long long)len);

Please can you test with the current version - the official repository should now be up to date with my version. Thanks.

Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
maintainer
#3 lore raw

PATCH v2 1/1 ARM: avoid Cortex-A9 livelock on tight dmb loops

Quoted 13 lines · Russell King - ARM Linux
Quoted 11 lines · Tony Lindgren

CONFIG_KERNEL_LZMA fails:

Try gzip decompression.
Try LZMA decompression.
lzma_decompress_file: read on /boot/zImage of 65536 bytes failed
kernel: 0xb6abb010 kernel_size: 0x43d0f0
MEMORY RANGES
0000000080000000-00000000bfdfffff (0)
zImage header: 0x016f2818 0x00000000 0x0043d0f0
zImage size 0x43d0f0, file size 0x43d0f0
Reserved memory ranges

Quoted 6 lines

This looks like an old kexec binary as it's missing the output from:

        dbgprintf("zImage requires 0x%08llx bytes\n", (unsigned long long)len);

Please can you test with the current version - the official repository should now be up to date with my version. Thanks.

OK great. After updating kexec-tools to latest git veresion LZMA crashkernel now also boots for me :)

Regards,

Tony

#4 lore raw

PATCH v2 1/1 ARM: avoid Cortex-A9 livelock on tight dmb loops

In reply to Russell King

Hi Russell,

Quoted 5 lines · Russell King

Executing loops such as:

	while (1)
		cpu_relax();
Quoted 8 lines

with interrupts disabled results in a livelock of the entire system, as other CPUs are prevented making progress. This is most noticable as a failure of crashdump kexec, which stops just after issuing:

Loading crashdump kernel...

to the system console. Two other locations of these loops within the ARM code have been identified and fixed up.

Can you confirm that this only happens if CONFIG_ARM_ERRATA_754327=y? The only erratum I can find for A9 that matches this behaviour exists when the body of the tight loop contains a DMB and some of the possible workarounds are:

- Add ten NOPs after the DMB
- Use DSB instead of DMB in the tight loop
- Set bit 16 in the diagnostic control register (p15, c1, 5, 0, c0, 1)

WFE is probably fine (the write-up isn't clear), but if this only occurs due to CONFIG_ARM_ERRATA_754327=y it would be nice to mitigate it in the alternative cpu_relax() definition itself, which isn't generally possible with WFE.

Will

#5 lore raw

PATCH v2 1/1 ARM: avoid Cortex-A9 livelock on tight dmb loops

Quoted 12 lines · Will Deacon

Hi Russell,

Quoted 9 lines · Russell King

Executing loops such as:

	while (1)
		cpu_relax();

with interrupts disabled results in a livelock of the entire system, as other CPUs are prevented making progress. This is most noticable as a failure of crashdump kexec, which stops just after issuing:

Quoted 6 lines
Quoted 4 lines

Loading crashdump kernel...

to the system console. Two other locations of these loops within the ARM code have been identified and fixed up.

Can you confirm that this only happens if CONFIG_ARM_ERRATA_754327=y?

CONFIG_ARM_ERRATA_754327=y + patch => works
CONFIG_ARM_ERRATA_754327=y => fails
CONFIG_ARM_ERRATA_754327=n => works

Quoted 7 lines

The only erratum I can find for A9 that matches this behaviour exists when the body of the tight loop contains a DMB and some of the possible workarounds are:

- Add ten NOPs after the DMB
- Use DSB instead of DMB in the tight loop
- Set bit 16 in the diagnostic control register (p15, c1, 5, 0, c0, 1)

Yes, I think you pointed me at that. It may be appropriate to mitigate the cases where we have a tight loop where the loop has a termination condition, but in these cases, all the loops are infinite - finding some way to avoid spinning in this case is probably a good idea in any case.

What I'm more interested in this patch is to fix kexec crashdump when CONFIG_ARM_ERRATA_754327=y on OMAP4 (and similar) platforms.

Quoted 4 lines

WFE is probably fine (the write-up isn't clear), but if this only occurs due to CONFIG_ARM_ERRATA_754327=y it would be nice to mitigate it in the alternative cpu_relax() definition itself, which isn't generally possible with WFE.

With the WFE, it is no longer "a tight loop", although WFE is just a hint to the processor, it could ultimately ignore it. That said, in all these cases, either:

- we're either talking about a secondary CPU, so SMP must be supported (which presumably guarantees implementation of SEV/WFE)
or:
- we're the only CPU so this problem doesn't apply to the infinite loop case.

Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up