x86, MCE, AMD: move invariant code out from loop body
A message that is not in the archive (sent off-list or not yet received): 1411377812.1917.112.camel@cyc
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 x86, MCE, AMD: move invariant code out from loop body
Quoted 20 lines · Borislav Petkov
Quoted 18 lines · Borislav Petkov
Quoted 17 lines · Chen Yucong
Hi Boris,
I have found the following code snippet in
mce_amd.c./* cpu init entry point, called from
mce.cwith preempt off */ voidmce_amd_feature_init(struct cpuinfo_x86 *c){ ... ... for (bank = 0; bank < mca_cfg.banks; ++bank) { for (block = 0; block < NR_BLOCKS; ++block) { ... ... mce_threshold_block_init(&b, offset); mce_threshold_vector = amd_threshold_interrupt; } } }
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Why should "
mce_threshold_vector=amd_threshold_interrupt" be placed in the inner loop body?Yeah, it was added sloppily with
b276268631af3, I'm not surprised. Feel free to send a fix.do you still want to send a fix or should I fix it up quickly?
From: Chen Yucong <[email protected]>
Subject: [PATCH] x86, MCE, AMD: move invariant code out from loop body
"mce_threshold_vector = amd_threshold_interrupt;" is loop invariant code in mce_amd_feature_init(). So it should be moved out from loop body.
--- arch/x86/kernel/cpu/mcheck/mce_amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/mcheck/mce_amd.c +2 -1
@@ -253,9 +253,10 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) }mce_threshold_block_init (&b, offset); - mce_threshold_vector = amd_threshold_interrupt; } } + + mce_threshold_vector = amd_threshold_interrupt; }/*
Signature · 1 line
1.7.10.4
Borislav Petkov
maintainerQuoted 16 lines · Chen Yucong
From: Chen Yucong <[email protected]>
Subject: [PATCH] x86, MCE, AMD: move invariant code out from loop body"
mce_threshold_vector=amd_threshold_interrupt;" is loop invariant code inmce_amd_feature_init(). So it should be moved out from loop body.Signed-off-by Chen Yucong <[email protected]>--- arch/x86/kernel/cpu/mcheck/mce_amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/x86/kernel/cpu/mcheck/mce_amd.c +0
-0
arch/x86/kernel/cpu/mcheck/mce_amd.c void mce_amd_feature_init(struct cpuinfo_x86 *c) · line 259
Quoted 8 lines
arch/x86/kernel/cpu/mcheck/mce_amd.c +2
-1@@ -253,9 +253,10 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) }mce_threshold_block_init (&b, offset); - mce_threshold_vector = amd_threshold_interrupt; } } + + mce_threshold_vector = amd_threshold_interrupt;
Looking at this more, it is theoretically possible that we break out of the both loops without *any* thresholding registers detected and to still assign a thresholding interrupt vector which would be clearly wrong.
Thus I think something like below should be much safer (I tried it with a label and goto already but it is uglier):
arch/x86/kernel/cpu/mcheck/mce_amd.c +3 -1
@@ -253,7 +253,9 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) }mce_threshold_block_init (&b, offset); - mce_threshold_vector = amd_threshold_interrupt; + +if (mce_threshold_vector != amd_threshold_interrupt) + mce_threshold_vector = amd_threshold_interrupt; } } }
Looking at the asm, we still go and fetch those addresses so not really a win:
cmpq $amd_threshold_interrupt, mce_threshold_vector(%rip) #, mce_threshold_vector je .L235 #, incl %r13d # block movq $amd_threshold_interrupt, mce_threshold_vector(%rip) #, mce_threshold_vector cmpl $9, %r13d #, block
but this way the code is relatively clean. Unless you can come up with a nicer, cleaner version to handle the breaking out in the success and failure case...
Hmmm.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Quoted 19 lines · Borislav Petkov
Quoted 18 lines · Chen Yucong
From: Chen Yucong <[email protected]>
Subject: [PATCH] x86, MCE, AMD: move invariant code out from loop body"
mce_threshold_vector=amd_threshold_interrupt;" is loop invariant code inmce_amd_feature_init(). So it should be moved out from loop body.Signed-off-by Chen Yucong <[email protected]>--- arch/x86/kernel/cpu/mcheck/mce_amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/x86/kernel/cpu/mcheck/mce_amd.c +0
-0@@ -253,9 +253,10 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) }
Quoted 11 lines
arch/x86/kernel/cpu/mcheck/mce_amd.c void mce_amd_feature_init(struct cpuinfo_x86 *c) · line 259
Quoted 6 lines
arch/x86/kernel/cpu/mcheck/mce_amd.c +2
-1mce_threshold_block_init (&b, offset); - mce_threshold_vector = amd_threshold_interrupt; } } + + mce_threshold_vector = amd_threshold_interrupt;Looking at this more, it is theoretically possible that we break out of the both loops without *any* thresholding registers detected and to still assign a thresholding interrupt vector which would be clearly wrong.
Yes! In this case, mce_threshold_vector should be `default_threshold_interrupt' rather than amd_threshold_interrupt.
Quoted 8 lines
Thus I think something like below should be much safer (I tried it with a label and goto already but it is uglier):
arch/x86/kernel/cpu/mcheck/mce_amd.c +0
-0
arch/x86/kernel/cpu/mcheck/mce_amd.c void mce_amd_feature_init(struct cpuinfo_x86 *c) · line 258
Quoted 7 lines
arch/x86/kernel/cpu/mcheck/mce_amd.c +3
-1@@ -253,7 +253,9 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) }mce_threshold_block_init (&b, offset); - mce_threshold_vector = amd_threshold_interrupt; + +if (mce_threshold_vector != amd_threshold_interrupt) + mce_threshold_vector = amd_threshold_interrupt;
Perhaps the above assignment operation should be put into
if (b.interrupt_capable) {
... ...
if (mce_threshold_vector != amd_threshold_interrupt)
mce_threshold_vector = amd_threshold_interrupt;
}If IntP (Thresholding Interrupt Supported) bit is zero, this indicates that the reporting of threshold overflow via interrupt isn't supported. So there's no need to execute the above assignment operation.
Quoted 13 lines
arch/x86/kernel/cpu/mcheck/mce_amd.c +0
-0} } }Looking at the asm, we still go and fetch those addresses so not really a win:
cmpq $amd_threshold_interrupt, mce_threshold_vector(%rip) #, mce_threshold_vector je .L235 #, incl %r13d # block movq $amd_threshold_interrupt, mce_threshold_vector(%rip) #, mce_threshold_vector cmpl $9, %r13d #, block
Quoted 3 lines
but this way the code is relatively clean. Unless you can come up with a nicer, cleaner version to handle the breaking out in the success and failure case...
Seems like I don't have any better idea than this.
thx!
cyc
From: Chen Yucong <[email protected]>
Subject: [PATCH] x86, MCE, AMD: avoid inappropriate assignment operation in
mce_amd_feature_init
Before executing "mce_threshold_vector = amd_threshold_interrupt;", a few conditions should be checked for avoiding inappropriate assignment operations, for example, IntP (Thresholding Interrupt Supported) bit of MCx_MISCi.
--- arch/x86/kernel/cpu/mcheck/mce_amd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/mcheck/mce_amd.c +4 -1
@@ -250,10 +250,13 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)if (b.interrupt_capable) {int new = (high &MASK_LVTOFF_HI ) >>20 ; offset =setup_APIC_mce (offset, new); + +if (offset == new && + mce_threshold_vector != amd_threshold_interrupt) + mce_threshold_vector = amd_threshold_interrupt; }mce_threshold_block_init (&b, offset); - mce_threshold_vector = amd_threshold_interrupt; } } }
Signature · 1 line
1.7.10.4