Skip to contentSkip to conversation

mtrr/x86/drivers: bury MTRR

PATCH In review Luis R. Rodriguez 34 participants 485 messages Mar 20, 2015 – Aug 1, 2015 Page 4 of 4

Subsystems (34)
lore
Share & tools
lore
#365 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

In reply to Josh Poimboeuf
Quoted 82 lines · Josh Poimboeuf
Quoted 14 lines · Ingo Molnar

Yeah, so many of these seem to be 'leaf only' functions: functions that don't ever call functions themselves.

So lets assume we always have CONFIG_FRAME_POINTERS=y.

If they don't set up a frame pointer then they in essence won't show up in the call chain - but normally they wouldn't because they call nothing.

If they trigger an exception/fault or if they get hit by an interrupt then I think we'll still correctly walk the stack - just those functions might be missing from the deterministic call chain, right? (it will still show up as a '?' entry.)

Quoted 5 lines

If they crash then we'll see them because the crashing RIP will be printed.

So I'm wondering what the x86 policy here should be: to create frame pointers in them or not. Cc:-ed a few more gents for thoughts.

After removing the frame pointer checks for leaf functions, and adding a check for all functions which jump outside of their scope, the number of defconfig warnings dropped from 89 -> 47. The Fedora config warning count dropped from 207 -> 83.

Here are the remaining 47 warnings for defconfig:

stackvalidate: arch/x86/ia32/ia32entry.o: ia32_sysenter_target() is missing frame pointer logic
stackvalidate: arch/x86/ia32/ia32entry.o: return instruction outside of a function at .entry.text+0x52e
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x359
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x19be
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x19e5
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x1c21
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x1ceb
stackvalidate: arch/x86/kernel/acpi/wakeup_64.o: unsupported jump to outside of the function at wakeup_long64+0x15
stackvalidate: arch/x86/kernel/acpi/wakeup_64.o: do_suspend_lowlevel() is missing frame pointer logic
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x6b
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0xc7
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x110
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x145
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x1c4
stackvalidate: arch/x86/kernel/head_64.o: return instruction outside of a function at .head.text+0x1a2
stackvalidate: arch/x86/kernel/head_64.o: early_idt_handler() is missing frame pointer logic
stackvalidate: arch/x86/platform/efi/efi_stub_64.o: efi_call() is missing frame pointer logic
stackvalidate: arch/x86/realmode/rm/trampoline_64.o: return instruction outside of a function at .text+0x170
stackvalidate: arch/x86/realmode/rm/trampoline_64.o: return instruction outside of a function at .text+0x176
stackvalidate: arch/x86/realmode/rm/reboot.o: return instruction outside of a function at .text+0x2a
stackvalidate: arch/x86/realmode/rm/copy.o: copy_from_fs() is missing frame pointer logic
stackvalidate: arch/x86/realmode/rm/copy.o: copy_to_fs() is missing frame pointer logic
stackvalidate: arch/x86/power/hibernate_asm_64.o: return instruction outside of a function at .text+0x69
stackvalidate: arch/x86/power/hibernate_asm_64.o: return instruction outside of a function at .text+0x16d
stackvalidate: arch/x86/lib/copy_user_64.o: unsupported jump to outside of the function at _copy_to_user+0x25
stackvalidate: arch/x86/lib/copy_user_64.o: unsupported jump to outside of the function at _copy_from_user+0x25
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_1+0x14
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_2+0x4
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_4+0x4
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_8+0x4
stackvalidate: arch/x86/lib/getuser.o: return instruction outside of a function at .text+0xc5
stackvalidate: arch/x86/lib/memmove_64.o: return instruction outside of a function at .altinstr_replacement+0x5
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_1+0x14
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_2+0x1b
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_4+0x1b
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_8+0x1b
stackvalidate: arch/x86/lib/putuser.o: return instruction outside of a function at .text+0xc1
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_down_read_failed() is missing frame pointer logic
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_down_write_failed() is missing frame pointer logic
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_wake() is missing frame pointer logic
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_downgrade_wake() is missing frame pointer logic
stackvalidate: arch/x86/boot/copy.o: copy_from_fs() is missing frame pointer logic
stackvalidate: arch/x86/boot/copy.o: copy_to_fs() is missing frame pointer logic
stackvalidate: arch/x86/boot/compressed/head_64.o: return instruction outside of a function at .text+0x16e
stackvalidate: arch/x86/boot/compressed/head_64.o: return instruction outside of a function at .text+0x172
stackvalidate: arch/x86/boot/compressed/head_64.o: startup_32() is missing frame pointer logic
stackvalidate: arch/x86/boot/pmjump.o: unsupported jump to outside of the function at in_pm32+0x1c

Note that only 13 of the 47 warnings are actually due to missing frame pointer logic. The rest are ambiguous conditions which prevent stackvalidate from being able to make sense of things: returning from outside of a proper ELF function, or jumping from inside of a function to outside of its scope.

Quoted 5 lines

Similarly, in the Fedora config case, only 27 of the 83 warnings are for missing frame pointer logic.

If there are no objections, I'll go with this approach in the next version of the patch set.

I'm willing to review anything with "entry" in its filename.

--Andy

#366 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

Quoted 62 lines · Andy Lutomirski
Quoted 61 lines · Josh Poimboeuf

After removing the frame pointer checks for leaf functions, and adding a check for all functions which jump outside of their scope, the number of defconfig warnings dropped from 89 -> 47. The Fedora config warning count dropped from 207 -> 83.

Here are the remaining 47 warnings for defconfig:

stackvalidate: arch/x86/ia32/ia32entry.o: ia32_sysenter_target() is missing frame pointer logic
stackvalidate: arch/x86/ia32/ia32entry.o: return instruction outside of a function at .entry.text+0x52e
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x359
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x19be
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x19e5
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x1c21
stackvalidate: arch/x86/kernel/entry_64.o: return instruction outside of a function at .entry.text+0x1ceb
stackvalidate: arch/x86/kernel/acpi/wakeup_64.o: unsupported jump to outside of the function at wakeup_long64+0x15
stackvalidate: arch/x86/kernel/acpi/wakeup_64.o: do_suspend_lowlevel() is missing frame pointer logic
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x6b
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0xc7
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x110
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x145
stackvalidate: arch/x86/kernel/relocate_kernel_64.o: return instruction outside of a function at .text+0x1c4
stackvalidate: arch/x86/kernel/head_64.o: return instruction outside of a function at .head.text+0x1a2
stackvalidate: arch/x86/kernel/head_64.o: early_idt_handler() is missing frame pointer logic
stackvalidate: arch/x86/platform/efi/efi_stub_64.o: efi_call() is missing frame pointer logic
stackvalidate: arch/x86/realmode/rm/trampoline_64.o: return instruction outside of a function at .text+0x170
stackvalidate: arch/x86/realmode/rm/trampoline_64.o: return instruction outside of a function at .text+0x176
stackvalidate: arch/x86/realmode/rm/reboot.o: return instruction outside of a function at .text+0x2a
stackvalidate: arch/x86/realmode/rm/copy.o: copy_from_fs() is missing frame pointer logic
stackvalidate: arch/x86/realmode/rm/copy.o: copy_to_fs() is missing frame pointer logic
stackvalidate: arch/x86/power/hibernate_asm_64.o: return instruction outside of a function at .text+0x69
stackvalidate: arch/x86/power/hibernate_asm_64.o: return instruction outside of a function at .text+0x16d
stackvalidate: arch/x86/lib/copy_user_64.o: unsupported jump to outside of the function at _copy_to_user+0x25
stackvalidate: arch/x86/lib/copy_user_64.o: unsupported jump to outside of the function at _copy_from_user+0x25
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_1+0x14
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_2+0x4
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_4+0x4
stackvalidate: arch/x86/lib/getuser.o: unsupported jump to outside of the function at __get_user_8+0x4
stackvalidate: arch/x86/lib/getuser.o: return instruction outside of a function at .text+0xc5
stackvalidate: arch/x86/lib/memmove_64.o: return instruction outside of a function at .altinstr_replacement+0x5
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_1+0x14
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_2+0x1b
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_4+0x1b
stackvalidate: arch/x86/lib/putuser.o: unsupported jump to outside of the function at __put_user_8+0x1b
stackvalidate: arch/x86/lib/putuser.o: return instruction outside of a function at .text+0xc1
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_down_read_failed() is missing frame pointer logic
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_down_write_failed() is missing frame pointer logic
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_wake() is missing frame pointer logic
stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_downgrade_wake() is missing frame pointer logic
stackvalidate: arch/x86/boot/copy.o: copy_from_fs() is missing frame pointer logic
stackvalidate: arch/x86/boot/copy.o: copy_to_fs() is missing frame pointer logic
stackvalidate: arch/x86/boot/compressed/head_64.o: return instruction outside of a function at .text+0x16e
stackvalidate: arch/x86/boot/compressed/head_64.o: return instruction outside of a function at .text+0x172
stackvalidate: arch/x86/boot/compressed/head_64.o: startup_32() is missing frame pointer logic
stackvalidate: arch/x86/boot/pmjump.o: unsupported jump to outside of the function at in_pm32+0x1c

Note that only 13 of the 47 warnings are actually due to missing frame pointer logic. The rest are ambiguous conditions which prevent stackvalidate from being able to make sense of things: returning from outside of a proper ELF function, or jumping from inside of a function to outside of its scope.

Quoted 7 lines
Quoted 5 lines

Similarly, in the Fedora config case, only 27 of the 83 warnings are for missing frame pointer logic.

If there are no objections, I'll go with this approach in the next version of the patch set.

I'm willing to review anything with "entry" in its filename.

Thanks. I think the "entry" warnings may be false positives, since that code isn't called by any C kernel code. (Now that I'm ignoring leaf functions, the ratio of false positives to true positives has gone up.)

The false positives for "return instruction outside of a function" can be marked with the RET_NOVALIDATE macro to tell stackvalidate to ignore the return instruction, or with FILE_NOVALIDATE to tell it to ignore the entire file.

I can add some patches to fix the warnings. I'll put you on CC for the "entry" changes.

Signature · 1 line
Josh
maintainer
#367 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

In reply to Josh Poimboeuf
Quoted 1 line · Josh Poimboeuf

stackvalidate: arch/x86/lib/memmove_64.o: return instruction outside of a function at .altinstr_replacement+0x5

That must be something like this:

0000000000000000 <.altinstr_replacement>:

   0:   48 89 d1                mov    %rdx,%rcx
   3:   f3 a4                   rep movsb %ds:(%rsi),%es:(%rdi)
   5:   c3                      retq

right?

In any case, anything with alternatives is probably a false positive because even if instructions appear outside of the containing function, they get patched in and are actually inside. Jump offsets get fixed up properly too. Should, at least :-)

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#368 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

Quoted 10 lines · Borislav Petkov
Quoted 1 line · Josh Poimboeuf

stackvalidate: arch/x86/lib/memmove_64.o: return instruction outside of a function at .altinstr_replacement+0x5

That must be something like this:

0000000000000000 <.altinstr_replacement>:

   0:   48 89 d1                mov    %rdx,%rcx
   3:   f3 a4                   rep movsb %ds:(%rsi),%es:(%rdi)
   5:   c3                      retq
Quoted 6 lines

right?

In any case, anything with alternatives is probably a false positive because even if instructions appear outside of the containing function, they get patched in and are actually inside. Jump offsets get fixed up properly too. Should, at least :-)

Hm, alternatives do complicate things a bit. It *is* a false positive, but not necessarily because its part of an alternative instruction block.

The above code would be patched into memmove(), which is a leaf function because it doesn't call any other functions. Leaf functions don't need frame pointer logic, so we can ignore them.

If instead the above code were patched into a non-leaf function, we'd have to change it to restore the frame pointer before returning.

Signature · 1 line
Josh
#369 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

Quoted 10 lines · Josh Poimboeuf

Hm, alternatives do complicate things a bit. It *is* a false positive, but not necessarily because its part of an alternative instruction block.

The above code would be patched into memmove(), which is a leaf function because it doesn't call any other functions. Leaf functions don't need frame pointer logic, so we can ignore them.

If instead the above code were patched into a non-leaf function, we'd have to change it to restore the frame pointer before returning.

Is this really only a problem of alternatives? How about dynamically-enabled tracepoints?

Signature · 2 lines
Jiri Kosina
SUSE Labs
#370 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

Quoted 10 lines · Jiri Kosina
Quoted 8 lines · Josh Poimboeuf

Hm, alternatives do complicate things a bit. It *is* a false positive, but not necessarily because its part of an alternative instruction block.

The above code would be patched into memmove(), which is a leaf function because it doesn't call any other functions. Leaf functions don't need frame pointer logic, so we can ignore them.

Quoted 5 lines
Quoted 2 lines

If instead the above code were patched into a non-leaf function, we'd have to change it to restore the frame pointer before returning.

Is this really only a problem of alternatives? How about dynamically-enabled tracepoints?

I think tracepoints are only in C code, right? stackvalidate only analyzes asm code, so it's not a concern for this patch set.

And I think tracepoints rely on normal call instructions, so they shouldn't cause any problems with frame pointers as far as I can tell.

Signature · 1 line
Josh
maintainer
#371 lore raw

Re: [PATCH v4 0/3] Compile-time stack frame pointer validation

In reply to Josh Poimboeuf
Quoted 2 lines · Josh Poimboeuf

If instead the above code were patched into a non-leaf function, we'd have to change it to restore the frame pointer before returning.

Not a problem, I think. One'll need to add the FP restoring before the retq.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#372 lore raw

cover x86, mwaitt: introduce AMD mwaitt support

Hi,

This patch set introduces a new instruction support on AMD Carrizo (Family 15h, Model 60h-6fh). It adds mwaitx idle function with a configurable timer. The user can configure the idle method and timer value via the idle kernel parameter.

Some discussions of the background, please see:
http://marc.info/?l=linux-kernel&m=143202042530498&w=2
http://marc.info/?l=linux-kernel&m=143161327003541&w=2

They are rebased on tip/sched/core.

Thanks,
Rui

Huang Rui (4):
x86, mwaitt: add monitorx and mwaitx instruction x86, mwaitt: introduce mwaitx idle with a configurable timer x86, mwaitt: add document to describe mwaitx
x86, mwait: fix redundant comment

 Documentation/kernel-parameters.txt | 10 ++++-
 arch/x86/include/asm/cpufeature.h   |  1 +
 arch/x86/include/asm/mwait.h        | 27 +++++++++++++
 arch/x86/include/asm/processor.h    |  2 +-
 arch/x86/kernel/process.c           | 81 ++++++++++++++++++++++++++++++++++++-
 5 files changed, 118 insertions(+), 3 deletions(-)
Signature · 1 line
2.1.0
#373 lore raw

RFC PATCH 1/4 x86, mwaitt: add monitorx and mwaitx instruction

On AMD Carrizo processors (Family 15h, Model 60h-6fh), there is a new feature called MWAITT (Mwait with a timer) as an extension of Monitor/Mwait.

MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration.

Compared with MONITOR/MWAIT, there are minor differences in opcode and input parameters.

MWAITX ECX[1]: enable timer if set
MWAITX EBX[31:0]: max wait time expressed in SW P0 clocks

The software P0 frequency is the same as the TSC frequency.

Max timeout = EBX/(TSC frequency)

---
 arch/x86/include/asm/cpufeature.h |  1 +
 arch/x86/include/asm/mwait.h      | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
arch/x86/include/asm/cpufeature.h +1 -0
index 3d6606f..3ef1f6e 100644
@@ -176,6 +176,7 @@
 #define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
 #define X86_FEATURE_BPEXT	(6*32+26) /* data breakpoint extension */
 #define X86_FEATURE_PERFCTR_L2	( 6*32+28) /* L2 performance counter extensions */
+#define X86_FEATURE_MWAITT	( 6*32+29) /* Mwait extension (MonitorX/MwaitX) */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
arch/x86/include/asm/mwait.h +25 -0
index 653dfa7..b91136f 100644
@@ -23,6 +23,14 @@ static inline void __monitor(const void *eax, unsigned long ecx,
 		     :: "a" (eax), "c" (ecx), "d"(edx));
 }
 
+static inline void __monitorx(const void *eax, unsigned long ecx,
+			     unsigned long edx)
+{
+	/* "monitorx %eax, %ecx, %edx;" */
+	asm volatile(".byte 0x0f, 0x01, 0xfa;"
+		     :: "a" (eax), "c" (ecx), "d"(edx));
+}
+
 static inline void __mwait(unsigned long eax, unsigned long ecx)
 {
 	/* "mwait %eax, %ecx;" */
@@ -30,6 +38,14 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
 		     :: "a" (eax), "c" (ecx));
 }
 
+static inline void __mwaitx(unsigned long eax, unsigned long ebx,
+		unsigned long ecx)
+{
+	/* "mwaitx %eax, %ebx, %ecx;" */
+	asm volatile(".byte 0x0f, 0x01, 0xfb;"
+		     :: "a" (eax), "b" (ebx), "c" (ecx));
+}
+
 static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 {
 	trace_hardirqs_on();
@@ -38,6 +54,15 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 		     :: "a" (eax), "c" (ecx));
 }
 
+static inline void __sti_mwaitx(unsigned long eax, unsigned long ebx,
+		unsigned long ecx)
+{
+	trace_hardirqs_on();
+	/* "mwaitx %eax, %ebx, %ecx;" */
+	asm volatile("sti; .byte 0x0f, 0x01, 0xfb;"
+		     :: "a" (eax), "b" (ebx), "c" (ecx));
+}
+
 /*
  * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
  * which can obviate IPI to trigger checking of need_resched.
Signature · 1 line
2.1.0
#374 lore raw

Re: [RFC PATCH 1/4] x86, mwaitt: add monitorx and mwaitx instruction

Quoted 4 lines · Huang Rui

On AMD Carrizo processors (Family 15h, Model 60h-6fh), there is a new feature called MWAITT (Mwait with a timer) as an extension of Monitor/Mwait.

Quoted 8 lines

MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration.

Compared with MONITOR/MWAIT, there are minor differences in opcode and input parameters.

MWAITX ECX[1]: enable timer if set
MWAITX EBX[31:0]: max wait time expressed in SW P0 clocks

What's the behavior if you set EBX to some value but don't enable the timer with ECX? Normal MWAIT?

Quoted 3 lines

The software P0 frequency is the same as the TSC frequency.

Max timeout = EBX/(TSC frequency)

That's max timeout in seconds then.

Quoted 23 lines
---
 arch/x86/include/asm/cpufeature.h |  1 +
 arch/x86/include/asm/mwait.h      | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
arch/x86/include/asm/cpufeature.h +1 -0
index 3d6606f..3ef1f6e 100644
@@ -176,6 +176,7 @@
 #define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
 #define X86_FEATURE_BPEXT	(6*32+26) /* data breakpoint extension */
 #define X86_FEATURE_PERFCTR_L2	( 6*32+28) /* L2 performance counter extensions */
+#define X86_FEATURE_MWAITT	( 6*32+29) /* Mwait extension (MonitorX/MwaitX) */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
arch/x86/include/asm/mwait.h +0 -0
index 653dfa7..b91136f 100644

arch/x86/include/asm/mwait.h static inline void __monitor(const void *eax, unsigned long ecx, · line 30

Quoted 8 lines
arch/x86/include/asm/mwait.h +5 -0
@@ -23,6 +23,14 @@ static inline void __monitor(const void *eax, unsigned long ecx,
 		     :: "a" (eax), "c" (ecx), "d"(edx));
 }
 
+static inline void __monitorx(const void *eax, unsigned long ecx,
+			     unsigned long edx)
+{
+	/* "monitorx %eax, %ecx, %edx;" */
+	asm volatile(".byte 0x0f, 0x01, 0xfa;"

Ah ok, ModRM extension to secondary opcode 0x1. Simply filling out the empty slots after SWAPGS, RDTSCP, ... :)

Quoted 22 lines
arch/x86/include/asm/mwait.h +11 -0
+		     :: "a" (eax), "c" (ecx), "d"(edx));
+}
+
 static inline void __mwait(unsigned long eax, unsigned long ecx)
 {
 	/* "mwait %eax, %ecx;" */
@@ -30,6 +38,14 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
 		     :: "a" (eax), "c" (ecx));
 }
 
+static inline void __mwaitx(unsigned long eax, unsigned long ebx,
+		unsigned long ecx)
+{
+	/* "mwaitx %eax, %ebx, %ecx;" */
+	asm volatile(".byte 0x0f, 0x01, 0xfb;"
+		     :: "a" (eax), "b" (ebx), "c" (ecx));
+}
+
 static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 {
 	trace_hardirqs_on();

arch/x86/include/asm/mwait.h static inline void __sti_mwait(unsigned long eax, unsigned long ecx) · line 58

Quoted 5 lines
arch/x86/include/asm/mwait.h +2 -0
@@ -38,6 +54,15 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 		     :: "a" (eax), "c" (ecx));
 }
 
+static inline void __sti_mwaitx(unsigned long eax, unsigned long ebx,
+		unsigned long ecx)

Please align the argument on the new line to the opening brace:

static inline void __sti_mwaitx(unsigned long eax, unsigned long ebx,
unsigned long ecx)

Quoted 13 lines
arch/x86/include/asm/mwait.h +7 -0
+{
+	trace_hardirqs_on();
+	/* "mwaitx %eax, %ebx, %ecx;" */
+	asm volatile("sti; .byte 0x0f, 0x01, 0xfb;"
+		     :: "a" (eax), "b" (ebx), "c" (ecx));
+}
+
 /*
  * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
  * which can obviate IPI to trigger checking of need_resched.
Signature · 1 line
2.1.0
Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#375 lore raw

Re: [RFC PATCH 1/4] x86, mwaitt: add monitorx and mwaitx instruction

Quoted 8 lines · Borislav Petkov
Quoted 7 lines · Huang Rui

On AMD Carrizo processors (Family 15h, Model 60h-6fh), there is a new feature called MWAITT (Mwait with a timer) as an extension of Monitor/Mwait.

MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration.

Quoted 9 lines
Quoted 5 lines

Compared with MONITOR/MWAIT, there are minor differences in opcode and input parameters.

MWAITX ECX[1]: enable timer if set
MWAITX EBX[31:0]: max wait time expressed in SW P0 clocks

What's the behavior if you set EBX to some value but don't enable the timer with ECX? Normal MWAIT?

Apology to late reply. I was having some AMD internal discussions and collecting more data about this feature these two days.

EBX will be unused if disable timer. You're right, then the behavior is like normal MWAIT. :)

Quoted 6 lines
Quoted 3 lines

The software P0 frequency is the same as the TSC frequency.

Max timeout = EBX/(TSC frequency)

That's max timeout in seconds then.

Actually, timeout = EBX * TSC cycle, EBX is the loop number that timer counts. This is 32-bit counter, and the maximum value is 0xffffffff.

Quoted 26 lines
Quoted 26 lines
---
 arch/x86/include/asm/cpufeature.h |  1 +
 arch/x86/include/asm/mwait.h      | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
arch/x86/include/asm/cpufeature.h +1 -0
index 3d6606f..3ef1f6e 100644
@@ -176,6 +176,7 @@
 #define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
 #define X86_FEATURE_BPEXT	(6*32+26) /* data breakpoint extension */
 #define X86_FEATURE_PERFCTR_L2	( 6*32+28) /* L2 performance counter extensions */
+#define X86_FEATURE_MWAITT	( 6*32+29) /* Mwait extension (MonitorX/MwaitX) */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
arch/x86/include/asm/mwait.h +0 -0
index 653dfa7..b91136f 100644
@@ -23,6 +23,14 @@ static inline void __monitor(const void *eax, unsigned long ecx,
 		     :: "a" (eax), "c" (ecx), "d"(edx));
 }
 
Quoted 9 lines

arch/x86/include/asm/mwait.h static inline void __monitor(const void *eax, unsigned long ecx, · line 30

Quoted 5 lines
arch/x86/include/asm/mwait.h +5 -0
+static inline void __monitorx(const void *eax, unsigned long ecx,
+			     unsigned long edx)
+{
+	/* "monitorx %eax, %ecx, %edx;" */
+	asm volatile(".byte 0x0f, 0x01, 0xfa;"

Ah ok, ModRM extension to secondary opcode 0x1. Simply filling out the empty slots after SWAPGS, RDTSCP, ... :)

Sorry, I might not get your meaning. Should it update like below:

asm volatile(".byte 0x0f, 0x01, 0xfa;"

             :: "a" (eax), "c" (ecx), "d" (edx));
                                        ^^^
Quoted 25 lines
Quoted 25 lines
arch/x86/include/asm/mwait.h +11 -0
+		     :: "a" (eax), "c" (ecx), "d"(edx));
+}
+
 static inline void __mwait(unsigned long eax, unsigned long ecx)
 {
 	/* "mwait %eax, %ecx;" */
@@ -30,6 +38,14 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
 		     :: "a" (eax), "c" (ecx));
 }
 
+static inline void __mwaitx(unsigned long eax, unsigned long ebx,
+		unsigned long ecx)
+{
+	/* "mwaitx %eax, %ebx, %ecx;" */
+	asm volatile(".byte 0x0f, 0x01, 0xfb;"
+		     :: "a" (eax), "b" (ebx), "c" (ecx));
+}
+
 static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 {
 	trace_hardirqs_on();
@@ -38,6 +54,15 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 		     :: "a" (eax), "c" (ecx));
 }
 
Quoted 7 lines

arch/x86/include/asm/mwait.h static inline void __sti_mwait(unsigned long eax, unsigned long ecx) · line 58

Quoted 2 lines
arch/x86/include/asm/mwait.h +2 -0
+static inline void __sti_mwaitx(unsigned long eax, unsigned long ebx,
+		unsigned long ecx)

Please align the argument on the new line to the opening brace:

static inline void __sti_mwaitx(unsigned long eax, unsigned long ebx,
unsigned long ecx)

Got it, thanks.

Thanks,
Rui

#376 lore raw

Re: [RFC PATCH 1/4] x86, mwaitt: add monitorx and mwaitx instruction

Quoted 5 lines · Huang Rui
Quoted 3 lines

Ah ok, ModRM extension to secondary opcode 0x1. Simply filling out the empty slots after SWAPGS, RDTSCP, ... :)

Sorry, I might not get your meaning.

No no - I was simply discussing the instruction encoding. Code is fine. :-)

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#377 lore raw

RFC PATCH 2/4 x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Huang Rui

MWAITX/MWAIT does not let the cpu core go into C1 state on AMD processors. The cpu core still consumes less power while waiting, and has faster exit from waiting than "Halt". This patch implements an interface using the kernel parameter "idle=" to configure mwaitx type and timer value.

If "idle=mwaitx", the timeout will be set as the maximum value ((2^64 - 1) * TSC cycle).
If "idle=mwaitx,100", the timeout will be set as 100ns. If the processor doesn't support MWAITX, then halt is used.

---
 arch/x86/include/asm/mwait.h     |  2 +
 arch/x86/include/asm/processor.h |  2 +-
 arch/x86/kernel/process.c        | 79 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)
arch/x86/include/asm/mwait.h +2 -0
index b91136f..c4e51e7 100644
@@ -14,6 +14,8 @@
 #define CPUID5_ECX_INTERRUPT_BREAK	0x2
 
 #define MWAIT_ECX_INTERRUPT_BREAK	0x1
+#define MWAITX_ECX_TIMER_ENABLE		0x2
+#define MWAITX_EBX_WAIT_TIMEOUT		0xffffffff
 
 static inline void __monitor(const void *eax, unsigned long ecx,
 			     unsigned long edx)
arch/x86/include/asm/processor.h +1 -1
index 23ba676..0f60e94 100644
@@ -733,7 +733,7 @@ extern unsigned long		boot_option_idle_override;
 extern bool			amd_e400_c1e_detected;
 
 enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
-			 IDLE_POLL};
+			 IDLE_POLL, IDLE_MWAITX};
 
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
arch/x86/kernel/process.c +79 -0

121 lines not on this page · raw message

Signature · 1 line
2.1.0
#378 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 9 lines · Huang Rui

MWAITX/MWAIT does not let the cpu core go into C1 state on AMD processors. The cpu core still consumes less power while waiting, and has faster exit from waiting than "Halt". This patch implements an interface using the kernel parameter "idle=" to configure mwaitx type and timer value.

If "idle=mwaitx", the timeout will be set as the maximum value ((2^64 - 1) * TSC cycle).
If "idle=mwaitx,100", the timeout will be set as 100ns. If the processor doesn't support MWAITX, then halt is used.

Ok, I see what you're trying here and I think this is not the optimal approach.

So let me explain how I see it, you correct me if I'm wrong:

So we want to do MWAITX so that we can save us idle entry/exit overhead with HLT. Because MWAITX is faster, reportedly.

Now, if we want to do that, we want to do it dynamically and adjust the MWAITX sleep interval depending on the system, usage pattern, system load and so on.

And for that we would need an adaptive scheme which approximates each idle interval. Simply taking TSC before we enter idle and after we come out would give us each idle residency duration and we can do some simple math to approximate it.

Now, what would that bring us: faster wakeup times.

And here comes the 10^6 $ question: why are we doing all the fun?

I'm thinking we want to find a cutoff duration where for smaller durations it is worth to do MWAITX and have faster entry/exit times and for bigger durations we want to do HLT because it'll get into C1E and give us higher power savings.

We don't want to do MWAITX too long because that'll burn more power relatively to HLT but we don't want to do HLT for shorter periods because then entry/exit costs.

Am I on the right track at least?

Quoted 12 lines
---
 arch/x86/include/asm/mwait.h     |  2 +
 arch/x86/include/asm/processor.h |  2 +-
 arch/x86/kernel/process.c        | 79 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)
arch/x86/include/asm/mwait.h +0 -0
index b91136f..c4e51e7 100644

arch/x86/include/asm/mwait.h line 17

Quoted 4 lines
arch/x86/include/asm/mwait.h +1 -0
@@ -14,6 +14,8 @@
 #define CPUID5_ECX_INTERRUPT_BREAK	0x2
 
 #define MWAIT_ECX_INTERRUPT_BREAK	0x1
+#define MWAITX_ECX_TIMER_ENABLE		0x2

Use BIT(1) here.

Quoted 56 lines
arch/x86/include/asm/mwait.h +1 -0
+#define MWAITX_EBX_WAIT_TIMEOUT		0xffffffff
 
 static inline void __monitor(const void *eax, unsigned long ecx,
 			     unsigned long edx)
arch/x86/include/asm/processor.h +1 -1
index 23ba676..0f60e94 100644
@@ -733,7 +733,7 @@ extern unsigned long		boot_option_idle_override;
 extern bool			amd_e400_c1e_detected;
 
 enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
-			 IDLE_POLL};
+			 IDLE_POLL, IDLE_MWAITX};
 
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
arch/x86/kernel/process.c +13 -0
index 6e338e3..9d68193 100644
@@ -30,6 +30,7 @@
 #include <asm/debugreg.h>
 #include <asm/nmi.h>
 #include <asm/tlbflush.h>
+#include <asm/x86_init.h>
 
 /*
  * per-CPU TSS segments. Thre ads are completely 'soft' on Linux,
@@ -276,6 +277,7 @@ unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
 EXPORT_SYMBOL(boot_option_idle_override);
 
 static void (*x86_idle)(void);
+static unsigned long idle_param;
 
 #ifndef CONFIG_SMP
 static inline void play_dead(void)
@@ -444,6 +446,17 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 	return 1;
 }
 
+static int not_support_mwaitx(const struct cpuinfo_x86 *c)
+{
+	if (c->x86_vendor != X86_VENDOR_AMD)
+		return 1;
+
+	if (!cpu_has(c, X86_FEATURE_MWAITT))
+		return 1;
+
+	return 0;
+}
+
 /*
  * MONITOR/MWAIT with no hints, used for default default C1 state.
  * This invokes MWAIT with interrutps enabled and no flags,

arch/x86/kernel/process.c static void mwait_idle(void) · line 487

Quoted 5 lines
arch/x86/kernel/process.c +2 -0
@@ -470,12 +483,45 @@ static void mwait_idle(void)
 	__current_clr_polling();
 }
 
+/*
+ * AMD Excavator processors support the new MONITORX/MWAITX instructions.

No need for that especially when newer than XV processors start supporting those too.

Quoted 5 lines
arch/x86/kernel/process.c +5 -0
+ * The function is similar to mwait but with a timer. On AMD platforms
+ * mwaitx does not let the core go into C1 state. This provides for a
+ * faster waiting exit speed. The user can configure the idle method and
+ * timer value via the idle kernel parameter.
+ */

...

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#379 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 10 lines · Borislav Petkov
Quoted 9 lines · Huang Rui

MWAITX/MWAIT does not let the cpu core go into C1 state on AMD processors. The cpu core still consumes less power while waiting, and has faster exit from waiting than "Halt". This patch implements an interface using the kernel parameter "idle=" to configure mwaitx type and timer value.

If "idle=mwaitx", the timeout will be set as the maximum value ((2^64 - 1) * TSC cycle).
If "idle=mwaitx,100", the timeout will be set as 100ns. If the processor doesn't support MWAITX, then halt is used.

So what does the hardware do with the timeout value?

Does it use it to decide how 'deep' a sleep it will go into, i.e. larger timeouts cause longer entry and exit latencies?

Or some other purpose?

I suppose it's also the case that if an interrupt arrives _before_ the expected timeout then MWAITX will try to exit immediately, it won't wait until the timeout, right?

Thanks,

Ingo

#380 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 2 lines · Ingo Molnar

Does it use it to decide how 'deep' a sleep it will go into, i.e. larger timeouts cause longer entry and exit latencies?

That's what the HLT thing does. Cores go into C1 and then at some point (hysteresis, etc) the whole core complex enters C1E.

The MWAIT* should be used for only shorter sleeps as it remains in C1. IMHO, of course.

But the problem there is another: what happens if the timeout fires, you wake up and see that you can remain idle? Do HLT? Do another MWAITX round?

This means you have an additional unnecessary wakeup which costs.

Quoted 3 lines

I suppose it's also the case that if an interrupt arrives _before_ the expected timeout then MWAITX will try to exit immediately, it won't wait until the timeout, right?

I'd assume so - I mean, it must, right.

BUT!, in talking to Andy about it last night on IRC, he pointed out that when using acpi_idle, we never come to calling x86_idle() and from looking quickly at cpuidle_idle_call(), that still might be the case as we go to use_default only when there's an error with the cpuidle driver or so.

So Rui, before you go and do more work on it, you should probably analyze what cpuidle exactly does (if you haven't done so yet). And on AMD we do use acpi_idle - at least on my F15h box that is the case:

$ grep . /sys/devices/system/cpu/cpuidle/current_*
/sys/devices/system/cpu/cpuidle/current_driver:acpi_idle
/sys/devices/system/cpu/cpuidle/current_governor_ro:menu

Thanks.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#381 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

Does it use it to decide how 'deep' a sleep it will go into, i.e. larger timeouts cause longer entry and exit latencies?

That's what the HLT thing does. Cores go into C1 and then at some point (hysteresis, etc) the whole core complex enters C1E.

Well, HLT does not get any hint from the OS how long the idling is expected to last.

So I don't think it's the same thing.

Quoted 6 lines

The MWAIT* should be used for only shorter sleeps as it remains in C1. IMHO, of course.

But the problem there is another: what happens if the timeout fires, you wake up and see that you can remain idle? Do HLT? Do another MWAITX round?

Another MWAITX round - we've got no crystal ball, so the hint might be wrong if an external event occurs that we did not anticipate.

As long as it's a statistical optimization it's OK: i.e. if the hardware only uses the timeout to determine how deep to sleep.

Quoted 1 line

This means you have an additional unnecessary wakeup which costs.

I don't think MWAITX will wake up in itself. (If yes then it's essentially a timer in disguise and needs a whole different approach!)

Quoted 11 lines
Quoted 3 lines

I suppose it's also the case that if an interrupt arrives _before_ the expected timeout then MWAITX will try to exit immediately, it won't wait until the timeout, right?

I'd assume so - I mean, it must, right.

BUT!, in talking to Andy about it last night on IRC, he pointed out that when using acpi_idle, we never come to calling x86_idle() and from looking quickly at cpuidle_idle_call(), that still might be the case as we go to use_default only when there's an error with the cpuidle driver or so.

Yes, we don't normally see these idle handlers, ACPI takes over on most systems.

Quoted 8 lines

So Rui, before you go and do more work on it, you should probably analyze what cpuidle exactly does (if you haven't done so yet). And on AMD we do use acpi_idle - at least on my F15h box that is the case:

$ grep . /sys/devices/system/cpu/cpuidle/current_*
/sys/devices/system/cpu/cpuidle/current_driver:acpi_idle
/sys/devices/system/cpu/cpuidle/current_governor_ro:menu

Yes.

The question would be: on systems that provide ACPI idle but also have MWAITX support, which one behaves better on the hardware side?

Thanks,

Ingo

#382 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 2 lines · Ingo Molnar

Well, HLT does not get any hint from the OS how long the idling is expected to last.

MWAIT on AMD doesn't either:

"EAX specifies optional hints for the MWAIT instruction. There are currently no hints defined and all bits should be 0. Setting a reserved bit in EAX is ignored by the processor."

I don't know about MWAITX though as I haven't seen any official doc yet.

Quoted 2 lines

Another MWAITX round - we've got no crystal ball, so the hint might be wrong if an external event occurs that we did not anticipate.

So if we end up doing a bunch of MWAITX rounds instead of HLT and MWAITX saves less power than HLT, then we practically are worse.

I think the idea with MWAITX is to use it to sleep only when you know the timeout would be shorter - whatever "shorter" means - and thus you can save yourself the idle entry/exit latency.

If you keep waking up due to timeout ending - which with u32 in EBX will be ~1sec on a 4GHz core, or 2 on a 2GHz core - and your MWAITX C-state is worse wrt power consumption than your HLT state, then you lose. And your MWAITX C-state *is* worse currently, see below.

Quoted 2 lines

I don't think MWAITX will wake up in itself. (If yes then it's essentially a timer in disguise and needs a whole different approach!)

I mean when the MWAITX timeout expires. When it does, we wake up.

Also, normal MWAIT allows for interrupts to wake it up:

"ECX specifies optional extensions for the MWAIT instruction. The only extension currently defined is ECX bit 0, which allows interrupts to wake MWAIT, even when eFLAGS.IF = 0. Support for this extension is indicated by a feature flage returned by the CPUID instruction."

Quoted 2 lines

The question would be: on systems that provide ACPI idle but also have MWAITX support, which one behaves better on the hardware side?

I'd venture a guess here that the ACPI side should be using all C-states available (think of other OSes and having optimal power savings there) and MWAITX would be worse or the same. Right now it is entering some funny state between C0 and C1 reportedly:

"But on AMD platform, mwaitx/mwait cannot go to C1 or C1E like intel. The power consumption of waiting phase is somewhere in between (C0 and C1). Actually, it's still in C0 but less power consumption than normal C0."

So my thinking currently is - provided we want to use it at all:

* Use MWAITX on entry to idle, considering that on a busy system, the statistical probability of this sleep timeout to be small, is high.

* When the timeout expires and we wake up and realize there's still nothing to do, we do HLT.

But all that is pointless if we end up in acpi_idle anyway...

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#383 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

Well, HLT does not get any hint from the OS how long the idling is expected to last.

MWAIT on AMD doesn't either:

Yeah, MWAIT clearly doesn't, but I was talking about MWAITX, which takes a timeout parameter as per these patches.

Quoted 6 lines
Quoted 3 lines

Another MWAITX round - we've got no crystal ball, so the hint might be wrong if an external event occurs that we did not anticipate.

So if we end up doing a bunch of MWAITX rounds instead of HLT and MWAITX saves less power than HLT, then we practically are worse.

So the way I think it would work ideally is (and note that this is different from how you think it works):

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

- based on the 'timeout' hint, MWAITX can internally optimize how deep sleep it enters. If the timeout is large it goes deep, if it's small, it goes shallow. This does not change the fact that no matter which state it enters, it will come back the moment an interrupt is posted.

if actual behavior departs from this ideal behavior then we need to know.

Quoted 5 lines
Quoted 3 lines

I don't think MWAITX will wake up in itself. (If yes then it's essentially a timer in disguise and needs a whole different approach!)

I mean when the MWAITX timeout expires. When it does, we wake up.

I'm not sure that's the case, see above what I think would be the ideal behavior.

If it's a true timeout, as you suggest, then I don't see any obvious way to support it, especially if it does not give access to deeper sleep states.

Quoted 1 line

Also, normal MWAIT allows for interrupts to wake it up:

of course! That's a necessary feature as otherwise we could stay stuck indefinitely.

This MWAIT extension:

Quoted 5 lines

"ECX specifies optional extensions for the MWAIT instruction. The only extension currently defined is ECX bit 0, which allows interrupts to wake MWAIT, even when eFLAGS.IF = 0. Support for this extension is indicated by a feature flage returned by the CPUID instruction."

is used by the Intel idle driver so that we can call MWAIT with interrupts disabled - but it behaves as if interrupts were enabled.

Quoted 16 lines
Quoted 3 lines

The question would be: on systems that provide ACPI idle but also have MWAITX support, which one behaves better on the hardware side?

I'd venture a guess here that the ACPI side should be using all C-states available (think of other OSes and having optimal power savings there) and MWAITX would be worse or the same. Right now it is entering some funny state between C0 and C1 reportedly:

"But on AMD platform, mwaitx/mwait cannot go to C1 or C1E like intel. The power consumption of waiting phase is somewhere in between (C0 and C1). Actually, it's still in C0 but less power consumption than normal C0."

So my thinking currently is - provided we want to use it at all:

Quoted 8 lines

* Use MWAITX on entry to idle, considering that on a busy system, the statistical probability of this sleep timeout to be small, is high.

* When the timeout expires and we wake up and realize there's still nothing to do, we do HLT.

But all that is pointless if we end up in acpi_idle anyway...

Yeah.

Thanks,

Ingo

#384 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 2 lines · Ingo Molnar

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

Let me quote the commit message:

"MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration."

You need to set the second bit in ECX to enable the timer.

I guess if you don't, then you get normal MWAIT but then you don't need the timeout either...

Quoted 3 lines

- based on the 'timeout' hint, MWAITX can internally optimize how deep sleep it enters. If the timeout is large it goes deep, if it's small, it goes shallow.

I haven't heard anything about handling the timeout this way and if it is not done this way, maybe Rui could forward this idea to hw people...

Quoted 3 lines

If it's a true timeout, as you suggest, then I don't see any obvious way to support it, especially if it does not give access to deeper sleep states.

Right.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#385 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

Let me quote the commit message:

"MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration."

Ah. A useful skill that is, being able to read.

Quoted 4 lines

You need to set the second bit in ECX to enable the timer.

I guess if you don't, then you get normal MWAIT but then you don't need the timeout either...

Yeah.

So if it's a true timeout then we could use it to implement irq-less
timers: that's actually pretty useful, because it could be faster than getting a local APIC timer irq, etc.

Thanks,

Ingo

#386 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 15 lines · Ingo Molnar
Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

Let me quote the commit message:

"MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration."

Ah. A useful skill that is, being able to read.

Quoted 2 lines

You need to set the second bit in ECX to enable the timer.

Quoted 8 lines
Quoted 2 lines

I guess if you don't, then you get normal MWAIT but then you don't need the timeout either...

Yeah.

So if it's a true timeout then we could use it to implement irq-less
timers: that's actually pretty useful, because it could be faster than getting a local APIC timer irq, etc.

Uurgh, NO NO NO!

We have enough trouble with non functional timers already, we do not need another variant of those.

We can supply the estimated sleep time though if that helps the PM controller underneath to select a state. That's more or less what we do in the governors as well.

Thanks,

tglx

#387 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 19 lines · Thomas Gleixner
Quoted 18 lines · Ingo Molnar
Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

Let me quote the commit message:

"MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration."

Ah. A useful skill that is, being able to read.

Quoted 4 lines

You need to set the second bit in ECX to enable the timer.

I guess if you don't, then you get normal MWAIT but then you don't need the timeout either...

Quoted 7 lines
Quoted 5 lines

Yeah.

So if it's a true timeout then we could use it to implement irq-less timers: that's actually pretty useful, because it could be faster than getting a local APIC timer irq, etc.

Uurgh, NO NO NO!

I know, I know :-)

The XP PIC was a nasty, broken hardware timer, and all x86 timer generations after that made the situation even worse.

Quoted 6 lines

We have enough trouble with non functional timers already, we do not need another variant of those.

We can supply the estimated sleep time though if that helps the PM controller underneath to select a state. That's more or less what we do in the governors as well.

That's not what appears to be happening here though: the MWAITX will return after the timeout.

Which isn't really useful unless we use it to drive timers.

So 'lets not use it' might be the sane answer.

Thanks,

Ingo

#388 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 4 lines

That's not what appears to be happening here though: the MWAITX will return after the timeout.

Which isn't really useful unless we use it to drive timers.

What about things like mdelay() ?

Alan

#389 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 6 lines · One Thousand Gnomes
Quoted 4 lines

That's not what appears to be happening here though: the MWAITX will return after the timeout.

Which isn't really useful unless we use it to drive timers.

What about things like mdelay() ?

It has an upper limit on the max timeout though: u32 TSC cycles.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#390 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 9 lines · Borislav Petkov
Quoted 6 lines · One Thousand Gnomes
Quoted 4 lines

That's not what appears to be happening here though: the MWAITX will return after the timeout.

Which isn't really useful unless we use it to drive timers.

What about things like mdelay() ?

It has an upper limit on the max timeout though: u32 TSC cycles.

Which would be good enough for mdelay/udelay I think, but we'd need to measure the time spend in MWAITT so we wont return early.

Something like this:

	  delay = usec_to_tsc(delay);
	  end = rdtsc() + delay;
	  while (1) {
		MWAITT(delay);
		now = rdtsc();
		if (end <= now)
		   	  break;
		delay = end - now;
	}

Now we'd need to add alternatives or some other mechanism to it to make this conditionally for those machines.

Not sure if it's worth the trouble.

Thanks,

tglx

#391 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 4 lines · Thomas Gleixner

Which would be good enough for mdelay/udelay I think, but we'd need to measure the time spend in MWAITT so we wont return early.

Something like this:

Yeah, with a check maybe:

Quoted 1 line
	  delay = usec_to_tsc(delay_usec);
	if (delay > ((1 << 32) - 1)) {
		mdelay(delay_usec);
		return;
	}
Quoted 2 lines
	  end = rdtsc() + delay;
	  while (1) {

I guess

		monitorx( ...);

first.

Quoted 9 lines
		MWAITT(delay);
		now = rdtsc();
		if (end <= now)
		   	  break;
		delay = end - now;
	}

Now we'd need to add alternatives or some other mechanism to it to make this conditionally for those machines.

alternative_call(mdelay, mdelayx, X86_FEATURE_MWAITT, /* no output */, timeout);

Something like that maybe.

Quoted 1 line

Not sure if it's worth the trouble.

Could be a use case for MWAITX in the kernel!

:-D

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#392 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 33 lines · Borislav Petkov
Quoted 4 lines · Thomas Gleixner

Which would be good enough for mdelay/udelay I think, but we'd need to measure the time spend in MWAITT so we wont return early.

Something like this:

Yeah, with a check maybe:

Quoted 1 line
	  delay = usec_to_tsc(delay_usec);
	if (delay > ((1 << 32) - 1)) {
		mdelay(delay_usec);
		return;
	}
Quoted 2 lines
	  end = rdtsc() + delay;
	  while (1) {

I guess

		monitorx( ...);

first.

Quoted 9 lines
		MWAITT(delay);
		now = rdtsc();
		if (end <= now)
		   	  break;
		delay = end - now;
	}

Now we'd need to add alternatives or some other mechanism to it to make this conditionally for those machines.

Quoted 8 lines

alternative_call(mdelay, mdelayx, X86_FEATURE_MWAITT, /* no output */, timeout);

Something like that maybe.

Quoted 1 line

Not sure if it's worth the trouble.

Could be a use case for MWAITX in the kernel!

Looks like good use case. Boris, could we try to implement it?

Thanks,
Rui

#393 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 1 line · Huang Rui

Looks like good use case. Boris, could we try to implement it?

Andy had some suggestions on how to do it here:

https://lkml.kernel.org/r/[email protected]

which should be doable. Also, you'd probably need to set ECX[0]=0b too, so that MWAITX doesn't get woken up by interrupts while MWAIT-ing with interrupts disabled. I.e., this sequence:

cli
rdtsc
shove the computed timeout into ebx
mov $2,%ecx # this enables the timer and disables IRQs while MWAITing
mwaitx
sti

The NMI argument is a problem though - if and NMI gets you out of MWAITX, a simple perf tool workload would kill all MWAITX executions. Which is bad. :-\

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#394 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 11 lines · Borislav Petkov
Quoted 1 line · Huang Rui

Looks like good use case. Boris, could we try to implement it?

Andy had some suggestions on how to do it here:

https://lkml.kernel.org/r/[email protected]

which should be doable. Also, you'd probably need to set ECX[0]=0b too, so that MWAITX doesn't get woken up by interrupts while MWAIT-ing with interrupts disabled. I.e., this sequence:

Quoted 6 lines

cli
rdtsc
shove the computed timeout into ebx
mov $2,%ecx # this enables the timer and disables IRQs while MWAITing
mwaitx
sti

I must be missing something. In this sequence, you're sleeping with IF=0 and ECX[0] = 0, so an IRQ won't get handled. Don't we want ECX[0] = 1?

Quoted 4 lines

The NMI argument is a problem though - if and NMI gets you out of MWAITX, a simple perf tool workload would kill all MWAITX executions. Which is bad. :-\

I'm not sure it's a show-stopper. NMI handlers are meant to be fast. If an NMI comes in between rdtsc and mwaitx, then we oversleep, but by at most the time it takes to handle an NMI, and nothing would have stopped us from oversleeping that long if an NMI came in right after mwaitx returned.

--Andy

#395 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 3 lines · Andy Lutomirski

I must be missing something. In this sequence, you're sleeping with IF=0 and ECX[0] = 0, so an IRQ won't get handled. Don't we want ECX[0] = 1?

Hmm, so actually we don't want to sleep with interrupts disabled. If ECX[0]=1b, then an interrupt will wake MWAIT. So then you have to do the loop thing as tglx suggested.

Quoted 9 lines
Quoted 3 lines

The NMI argument is a problem though - if and NMI gets you out of MWAITX, a simple perf tool workload would kill all MWAITX executions. Which is bad. :-\

I'm not sure it's a show-stopper. NMI handlers are meant to be fast. If an NMI comes in between rdtsc and mwaitx, then we oversleep, but by at most the time it takes to handle an NMI, and nothing would have stopped us from oversleeping that long if an NMI came in right after mwaitx returned.

Actually, I'm thinking about an NMI happening after we've issued MWAIT. NMIs wake it up. So you have the same problem as above:

NMIs will wake MWAIT so you'd need to check how long you've slept and sleep for the remaining time. I.e., something like that thing from a couple of mails ago:

	delay = usec_to_tsc(delay_usec);

        if (delay > ((1 << 32) - 1)) {
                mdelay(delay_usec);
                return;
        }

	end = rdtsc() + delay;
	while (1) {

		monitorx( ...); /* Do we need that here? */
		mwaitx(delay);

		/* possible wakeups */

		now = rdtsc();
		if (end <= now)
			break;
		delay = end - now;
	}

Yes, no?

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#396 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 48 lines · Borislav Petkov
Quoted 3 lines · Andy Lutomirski

I must be missing something. In this sequence, you're sleeping with IF=0 and ECX[0] = 0, so an IRQ won't get handled. Don't we want ECX[0] = 1?

Hmm, so actually we don't want to sleep with interrupts disabled. If ECX[0]=1b, then an interrupt will wake MWAIT. So then you have to do the loop thing as tglx suggested.

Quoted 9 lines
Quoted 3 lines

The NMI argument is a problem though - if and NMI gets you out of MWAITX, a simple perf tool workload would kill all MWAITX executions. Which is bad. :-\

I'm not sure it's a show-stopper. NMI handlers are meant to be fast. If an NMI comes in between rdtsc and mwaitx, then we oversleep, but by at most the time it takes to handle an NMI, and nothing would have stopped us from oversleeping that long if an NMI came in right after mwaitx returned.

Actually, I'm thinking about an NMI happening after we've issued MWAIT. NMIs wake it up. So you have the same problem as above:

NMIs will wake MWAIT so you'd need to check how long you've slept and sleep for the remaining time. I.e., something like that thing from a couple of mails ago:

        delay = usec_to_tsc(delay_usec);

        if (delay > ((1 << 32) - 1)) {
                mdelay(delay_usec);
                return;
        }

        end = rdtsc() + delay;
        while (1) {

                monitorx( ...); /* Do we need that here? */
                mwaitx(delay);

                /* possible wakeups */

                now = rdtsc();
                if (end <= now)
                        break;
                delay = end - now;
        }
Quoted 1 line

Yes, no?

Yes, but there should already be an adequate outer loop around the whole thing. After all, even regular mwait can have spurious wakeups due to monitor monitoring the entire cache line.

--Andy

#397 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Borislav Petkov
Quoted 11 lines · Borislav Petkov
Quoted 1 line · Huang Rui

Looks like good use case. Boris, could we try to implement it?

Andy had some suggestions on how to do it here:

https://lkml.kernel.org/r/[email protected]

which should be doable. Also, you'd probably need to set ECX[0]=0b too, so that MWAITX doesn't get woken up by interrupts while MWAIT-ing with interrupts disabled. I.e., this sequence:

Quoted 6 lines

cli
rdtsc
shove the computed timeout into ebx
mov $2,%ecx # this enables the timer and disables IRQs while MWAITing
mwaitx
sti

And the above sucks for udelay, because you disable interrupts for random amounts of time.

Thanks,

tglx

#398 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Borislav Petkov
Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

Let me quote the commit message:

Quoted 7 lines

"MWAITT, another name is MWAITX (MWAIT with extensions), has a configurable timer that causes MWAITX to exit on expiration."

You need to set the second bit in ECX to enable the timer.

I guess if you don't, then you get normal MWAIT but then you don't need the timeout either...

That's right.

This feature will expose on Family 15h, Model 60-6fh. Just check the
http://developer.amd.com, sorry, I don't know why APM still doesn't update. But I can raise your question to HW guys.

Quoted 8 lines
Quoted 4 lines

- based on the 'timeout' hint, MWAITX can internally optimize how deep sleep it enters. If the timeout is large it goes deep, if it's small, it goes shallow.

I haven't heard anything about handling the timeout this way and if it is not done this way, maybe Rui could forward this idea to hw people...

Actually, there is another use case on HSA stack. The timer is used for synchronization between CPU and GPU. The CPU core will exit waiting when GPU thread modifies the monitoring address or the timer expires. :)

Thanks,
Rui

#399 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Ingo Molnar
Quoted 23 lines · Ingo Molnar
Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

Well, HLT does not get any hint from the OS how long the idling is expected to last.

MWAIT on AMD doesn't either:

Yeah, MWAIT clearly doesn't, but I was talking about MWAITX, which takes a timeout parameter as per these patches.

Quoted 6 lines
Quoted 3 lines

Another MWAITX round - we've got no crystal ball, so the hint might be wrong if an external event occurs that we did not anticipate.

So if we end up doing a bunch of MWAITX rounds instead of HLT and MWAITX saves less power than HLT, then we practically are worse.

So the way I think it would work ideally is (and note that this is different from how you think it works):

Quoted 8 lines

- MWAITX takes a 'timeout' parameter, but otherwise behaves exactly like MWAIT: i.e. once idle it won't exit idle on its own

- based on the 'timeout' hint, MWAITX can internally optimize how deep sleep it enters. If the timeout is large it goes deep, if it's small, it goes shallow. This does not change the fact that no matter which state it enters, it will come back the moment an interrupt is posted.

No, the timeout value doesn't decide how 'deep' the power state enters. Basically, the same power consumption with any timeout.

I summarized the comparison of mwait and mwaitx

MWAIT MWAITX
opcode 0f 01 c9 | 0f 01 fb
ECX[0] value of RFLAGS.IF seen by instruction
ECX[1] unused/#GP if set | enable timer if set
ECX[31:2] unused/#GP if set
EAX unused
EBX[31:0] unused | max wait time (loops)

MONITOR MONITORX
opcode 0f 01 c8 | 0f 01 fa
EAX (logical) address to monitor
ECX #GP if not zero

Thanks,
Rui

#400 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 14 lines · Huang Rui

No, the timeout value doesn't decide how 'deep' the power state enters. Basically, the same power consumption with any timeout.

I summarized the comparison of mwait and mwaitx

MWAIT MWAITX
opcode 0f 01 c9 | 0f 01 fb
ECX[0] value of RFLAGS.IF seen by instruction
ECX[1] unused/#GP if set | enable timer if set
ECX[31:2] unused/#GP if set
EAX unused
EBX[31:0] unused | max wait time (loops)

Quoted 4 lines

MONITOR MONITORX
opcode 0f 01 c8 | 0f 01 fa
EAX (logical) address to monitor
ECX #GP if not zero

Ok, thanks for the clarification!

Thanks,

Ingo

#401 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Borislav Petkov
Quoted 28 lines · Borislav Petkov
Quoted 2 lines · Ingo Molnar

Does it use it to decide how 'deep' a sleep it will go into, i.e. larger timeouts cause longer entry and exit latencies?

That's what the HLT thing does. Cores go into C1 and then at some point (hysteresis, etc) the whole core complex enters C1E.

The MWAIT* should be used for only shorter sleeps as it remains in C1. IMHO, of course.

But the problem there is another: what happens if the timeout fires, you wake up and see that you can remain idle? Do HLT? Do another MWAITX round?

This means you have an additional unnecessary wakeup which costs.

Quoted 3 lines

I suppose it's also the case that if an interrupt arrives _before_ the expected timeout then MWAITX will try to exit immediately, it won't wait until the timeout, right?

I'd assume so - I mean, it must, right.

BUT!, in talking to Andy about it last night on IRC, he pointed out that when using acpi_idle, we never come to calling x86_idle() and from looking quickly at cpuidle_idle_call(), that still might be the case as we go to use_default only when there's an error with the cpuidle driver or so.

Quoted 8 lines

So Rui, before you go and do more work on it, you should probably analyze what cpuidle exactly does (if you haven't done so yet). And on AMD we do use acpi_idle - at least on my F15h box that is the case:

$ grep . /sys/devices/system/cpu/cpuidle/current_*
/sys/devices/system/cpu/cpuidle/current_driver:acpi_idle
/sys/devices/system/cpu/cpuidle/current_governor_ro:menu

OK, I know. Thanks to reminder. :)

Thanks,
Rui

#402 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Borislav Petkov
Quoted 14 lines · Borislav Petkov
Quoted 9 lines · Huang Rui

MWAITX/MWAIT does not let the cpu core go into C1 state on AMD processors. The cpu core still consumes less power while waiting, and has faster exit from waiting than "Halt". This patch implements an interface using the kernel parameter "idle=" to configure mwaitx type and timer value.

If "idle=mwaitx", the timeout will be set as the maximum value ((2^64 - 1) * TSC cycle).
If "idle=mwaitx,100", the timeout will be set as 100ns. If the processor doesn't support MWAITX, then halt is used.

Ok, I see what you're trying here and I think this is not the optimal approach.

Quoted 8 lines

So let me explain how I see it, you correct me if I'm wrong:

So we want to do MWAITX so that we can save us idle entry/exit overhead with HLT. Because MWAITX is faster, reportedly.

Now, if we want to do that, we want to do it dynamically and adjust the MWAITX sleep interval depending on the system, usage pattern, system load and so on.

Yes, that's right. Maybe, even we can also find any other use case on kernel other components.

Quoted 10 lines

And for that we would need an adaptive scheme which approximates each idle interval. Simply taking TSC before we enter idle and after we come out would give us each idle residency duration and we can do some simple math to approximate it.

Now, what would that bring us: faster wakeup times.

And here comes the 10^6 $ question: why are we doing all the fun?

Do you mention the below codes:

/*
* TSC loops (EBX input) = Timer(nsec) *
* TSC freq(khz) / 1000000
*/
timeout = timeout * tsc_freq;
do_div(timeout, 1000000);

That's because the unit of tsc_freq is KHz and the unit of timeout is nanosecond. Then I do div 10^6 to figure out the corresponding loops.

Quoted 10 lines

I'm thinking we want to find a cutoff duration where for smaller durations it is worth to do MWAITX and have faster entry/exit times and for bigger durations we want to do HLT because it'll get into C1E and give us higher power savings.

We don't want to do MWAITX too long because that'll burn more power relatively to HLT but we don't want to do HLT for shorter periods because then entry/exit costs.

Am I on the right track at least?

Yes, that's totally right.

Quoted 15 lines
Quoted 15 lines
---
 arch/x86/include/asm/mwait.h     |  2 +
 arch/x86/include/asm/processor.h |  2 +-
 arch/x86/kernel/process.c        | 79 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)
arch/x86/include/asm/mwait.h +0 -0
index b91136f..c4e51e7 100644
@@ -14,6 +14,8 @@
 #define CPUID5_ECX_INTERRUPT_BREAK	0x2
 
Quoted 4 lines

arch/x86/include/asm/mwait.h line 17

Quoted 2 lines
arch/x86/include/asm/mwait.h +1 -0
 #define MWAIT_ECX_INTERRUPT_BREAK	0x1
+#define MWAITX_ECX_TIMER_ENABLE		0x2

Use BIT(1) here.

OK.

Quoted 60 lines
Quoted 60 lines
arch/x86/include/asm/mwait.h +1 -0
+#define MWAITX_EBX_WAIT_TIMEOUT		0xffffffff
 
 static inline void __monitor(const void *eax, unsigned long ecx,
 			     unsigned long edx)
arch/x86/include/asm/processor.h +1 -1
index 23ba676..0f60e94 100644
@@ -733,7 +733,7 @@ extern unsigned long		boot_option_idle_override;
 extern bool			amd_e400_c1e_detected;
 
 enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
-			 IDLE_POLL};
+			 IDLE_POLL, IDLE_MWAITX};
 
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
arch/x86/kernel/process.c +13 -0
index 6e338e3..9d68193 100644
@@ -30,6 +30,7 @@
 #include <asm/debugreg.h>
 #include <asm/nmi.h>
 #include <asm/tlbflush.h>
+#include <asm/x86_init.h>
 
 /*
  * per-CPU TSS segments. Thre ads are completely 'soft' on Linux,
@@ -276,6 +277,7 @@ unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
 EXPORT_SYMBOL(boot_option_idle_override);
 
 static void (*x86_idle)(void);
+static unsigned long idle_param;
 
 #ifndef CONFIG_SMP
 static inline void play_dead(void)
@@ -444,6 +446,17 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 	return 1;
 }
 
+static int not_support_mwaitx(const struct cpuinfo_x86 *c)
+{
+	if (c->x86_vendor != X86_VENDOR_AMD)
+		return 1;
+
+	if (!cpu_has(c, X86_FEATURE_MWAITT))
+		return 1;
+
+	return 0;
+}
+
 /*
  * MONITOR/MWAIT with no hints, used for default default C1 state.
  * This invokes MWAIT with interrutps enabled and no flags,
@@ -470,12 +483,45 @@ static void mwait_idle(void)
 	__current_clr_polling();
 }
 
Quoted 6 lines

arch/x86/kernel/process.c static void mwait_idle(void) · line 487

Quoted 2 lines
arch/x86/kernel/process.c +2 -0
+/*
+ * AMD Excavator processors support the new MONITORX/MWAITX instructions.

No need for that especially when newer than XV processors start supporting those too.

OK, got it.

Thanks,
Rui

maintainer
#403 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Huang Rui
Quoted 9 lines · Huang Rui

MWAITX/MWAIT does not let the cpu core go into C1 state on AMD processors. The cpu core still consumes less power while waiting, and has faster exit from waiting than "Halt". This patch implements an interface using the kernel parameter "idle=" to configure mwaitx type and timer value.

If "idle=mwaitx", the timeout will be set as the maximum value ((2^64 - 1) * TSC cycle).
If "idle=mwaitx,100", the timeout will be set as 100ns. If the processor doesn't support MWAITX, then halt is used.

I think this is wrong way to do this...

arch/x86/kernel/process.c static int __init idle_setup(char *str) · line 581

Quoted 1 line
arch/x86/kernel/process.c +1 -0
+		x86_idle = mwaitx_idle;

...this is a legacy thing. The modern idle path is cpuidle_idle_call, I believe, that that goes through the cpuidle subsystem, which has little to do with any of this.

Where is the MWAITX documentation? It seems that AMD has failed to update the obvious reference:

http://developer.amd.com/resources/documentation-articles/developer-guides-manuals/

From my vague understanding, MWAITX accepts a 32-bit maximum number of TSC ticks to wait. If that's correct, and it's not too late to change, then: AMD, you blew it. The correct way to do this would be to accept a 64-bit absolute TSC deadline.

The 32-bit relative timeout model utterly sucks for two reasons. Suppose we tried to use it. We'd have two major issues:

1. We can't sleep more than about 1.5 seconds because we'll overflow the deadline.

2. The relative timeout is annoying. Imagine:

rdtsc
shove the computed timeout into ebx
<-- IRQ here
mwaitx

now we sleep too long.

We can do:

cli
rdtsc
shove the computed timeout into ebx
mov $1,%ecx
mwaitx
sti

but that's annoying and isn't really correct wrt NMIs.

So this sucks.

In any event, I think this is barely useful.

That being said, it might be worth teaching the timer code about a magical ideal type of clock that is simultaneously a perfect invariant high-res clocksource *and* a very fast (in fact free) wakeup source that uses the same time base. In fact, Sandy Bridge and newer Intel CPUs have such a thing: it's called the TSC deadline timer. I think it's much faster to reprogram than other timers, and it ought to avoid a whole bunch of complicated messy code that handles the fact that crappier timers have their own crappy time bases.

If we did that *and* we had a non-crappy mwaitx, then we could apply an optimization: when going idle, we could turn off the TSC deadline timer and use mwaitx instead. This would about an interrupt if the event that wakes us is our timer.

In the mean time, I don't really see the point.

John, Peter, Thomas: would it actually make sense to teach the core timer/clockevent code about perfect time sources like invariant TSC + TSC deadline? AFAICT right now we're not doing anything particularly interesting with the TSC deadline timer.

--Andy

#404 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 2 lines · Andy Lutomirski

If we did that *and* we had a non-crappy mwaitx, then we could apply an optimization: when going idle, we could turn off the TSC deadline timer and use mwaitx instead. This would about an interrupt if the event that wakes us is our timer.

Hey, Intel, want to document your secret "Timed MWAIT" feature? It causes a transition to C0 when the deadline expires (see 4.2.4 of the Desktop 4th Generation Intel Core Processor Family Datasheet Volume 1, order number 328897-001) and it even has an erratum (HSD63 / BDM32), but the instruction itself doesn't appear to be documented.

--Andy

#405 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 10 lines · Andy Lutomirski
Quoted 2 lines · Andy Lutomirski

If we did that *and* we had a non-crappy mwaitx, then we could apply an optimization: when going idle, we could turn off the TSC deadline timer and use mwaitx instead. This would about an interrupt if the event that wakes us is our timer.

Hey, Intel, want to document your secret "Timed MWAIT" feature? It causes a transition to C0 when the deadline expires (see 4.2.4 of the Desktop 4th Generation Intel Core Processor Family Datasheet Volume 1, order number 328897-001) and it even has an erratum (HSD63 / BDM32), but the instruction itself doesn't appear to be documented.

Found more:

https://chromium-review.googlesource.com/#/c/205161/

Oddly, Coreboot seems to have mis-spelled that MSR. It's MSR_PKG_CST_CONFIG_CONTROL, and bit 31 isn't defined in the SDM (unsurprisingly).

--Andy

#406 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

Quoted 5 lines · Andy Lutomirski

https://chromium-review.googlesource.com/#/c/205161/

Oddly, Coreboot seems to have mis-spelled that MSR. It's MSR_PKG_CST_CONFIG_CONTROL, and bit 31 isn't defined in the SDM (unsurprisingly).

Since this MSR is a control MSR and from looking at the comment in the coreboot code and how they set that bit, it enables that MWAIT variant. Even if the MSR write would stick on your hw, though, you'd still need to know what it takes into EAX/ECX (and possibly some other register... EBX, EDX...?) It might bring you some fun while trying to figure it out :-)

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#407 lore raw

Re: [RFC PATCH 2/4] x86, mwaitt: introduce mwaitx idle with a configurable timer

In reply to Andy Lutomirski
Quoted 2 lines · Andy Lutomirski

John, Peter, Thomas: would it actually make sense to teach the core timer/clockevent code about perfect time sources like invariant TSC + TSC

Perfect? There is no such concept in timer land.

Quoted 2 lines

deadline? AFAICT right now we're not doing anything particularly interesting with the TSC deadline timer.

Interesting in what way? We still have to convert from and to nanoseconds and deal with the clock skew ....

Thanks,

tglx

#408 lore raw

RFC PATCH 3/4 x86, mwaitt: add document to describe mwaitx

In reply to Huang Rui

This patch adds a description in the kernel parameters documentation for "idle=mwaitx".

---
 Documentation/kernel-parameters.txt | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
Documentation/kernel-parameters.txt +9 -1
index 61ab162..af88c5c 100644
@@ -1363,7 +1363,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			Claim all unknown PCI IDE storage controllers.
 
 	idle=		[X86]
-			Format: idle=poll, idle=halt, idle=nomwait
+			Format: idle=poll, idle=halt, idle=nomwait,
+				idle=mwaitx[,<timer value>]
 			Poll forces a polling idle loop that can slightly
 			improve the performance of waking up a idle CPU, but
 			will use a lot of power and make the system run hot.
@@ -1371,6 +1372,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			idle=halt: Halt is forced to be used for CPU idle.
 			In such case C2/C3 won't be used again.
 			idle=nomwait: Disable mwait for CPU C-states
+			idle=mwaitx[,<timer value>]: Enable mwaitx and
+			configure max waiting timeout value (usec) for CPU
+			idle. If <timer value> is not specified, the
+			maximum timeout value (ebx=0xffffffff * TSC cycle)
+			will be used.  If <timer value> is specified as
+			zero, the timer is disabled. Waiting exits via
+			other reasons, such as an IPI.
 
 	ignore_loglevel	[KNL]
 			Ignore loglevel setting - this will print /all/
Signature · 1 line
2.1.0
#409 lore raw

RFC PATCH 4/4 x86, mwait: fix redundant comment

In reply to Huang Rui

This patch removes the redundant comment.

---
 arch/x86/kernel/process.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/process.c +1 -1
index 9d68193..e3e12b6 100644
@@ -458,7 +458,7 @@ static int not_support_mwaitx(const struct cpuinfo_x86 *c)
 }
 
 /*
- * MONITOR/MWAIT with no hints, used for default default C1 state.
+ * MONITOR/MWAIT with no hints, used for default C1 state.
  * This invokes MWAIT with interrutps enabled and no flags,
  * which is backwards compatible with the original MWAIT implementation.
  */
Signature · 1 line
2.1.0
#410 lore raw

Re: [RFC PATCH 4/4] x86, mwait: fix redundant comment

Quoted 12 lines · Huang Rui

This patch removes the redundant comment.

---
 arch/x86/kernel/process.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/process.c +0 -0
index 9d68193..e3e12b6 100644

arch/x86/kernel/process.c static int not_support_mwaitx(const struct cpuinfo_x86 *c) · line 464

Quoted 8 lines
arch/x86/kernel/process.c +1 -1
@@ -458,7 +458,7 @@ static int not_support_mwaitx(const struct cpuinfo_x86 *c)
 }
 
 /*
- * MONITOR/MWAIT with no hints, used for default default C1 state.
+ * MONITOR/MWAIT with no hints, used for default C1 state.
  * This invokes MWAIT with interrutps enabled and no flags,
  * which is backwards compatible with the original MWAIT implementation.
  */

Applied, thanks.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#411 lore raw

Re: [RFC PATCH 0/4] x86, mwaitt: introduce AMD mwaitt support

In reply to Huang Rui
Quoted 7 lines · Huang Rui

Hi,

This patch set introduces a new instruction support on AMD Carrizo (Family 15h, Model 60h-6fh). It adds mwaitx idle function with a configurable timer. The user can configure the idle method and timer value via the idle kernel parameter.

Quoted 5 lines

Some discussions of the background, please see:
http://marc.info/?l=linux-kernel&m=143202042530498&w=2
http://marc.info/?l=linux-kernel&m=143161327003541&w=2

They are rebased on tip/sched/core.

Just a note for the future - please use tip/master to base your patches on.

Thanks.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#412 lore raw

Re: [RFC PATCH 0/4] x86, mwaitt: introduce AMD mwaitt support

Quoted 8 lines · Borislav Petkov
Quoted 7 lines · Huang Rui

Hi,

This patch set introduces a new instruction support on AMD Carrizo (Family 15h, Model 60h-6fh). It adds mwaitx idle function with a configurable timer. The user can configure the idle method and timer value via the idle kernel parameter.

Quoted 9 lines
Quoted 5 lines

Some discussions of the background, please see:
http://marc.info/?l=linux-kernel&m=143202042530498&w=2
http://marc.info/?l=linux-kernel&m=143161327003541&w=2

They are rebased on tip/sched/core.

Just a note for the future - please use tip/master to base your patches on.

OK, I got it.

Thanks,
Rui

#413 lore raw

PATCH 1/1 x86, cpuinfo x86_model_id whitespace cleanup

When comparing 'model name' fields in /proc/cpuinfo it was noticed that a simple test comparing the model name fields was failing. After some quick investigation it was noticed that the model name fields were actually different -- processor 0's model name field had trailing white space removed, while the other processors did not.

Another way of seeing this behaviour is to convert spaces into underscores in the output of /proc/cpuinfo,

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

which shows two different model name fields even though they should be the same.

This occurs because the kernel calls strim() on cpu 0's x86_model_id field to output a pretty message to the console in print_cpu_info(), and as a result truncates the whitespace at the end of the x86_model_id field.

The x86_model_id field should be the same for the same processors. This patch uses string functions to remove both leading and trailing whitespace in the x86_model_id field. As a result the print_cpu_info() output looks like

smpboot: CPU0: AMD Opteron(TM) Processor 6272 (fam: 15, model: 01, stepping: 02)

and the x86_model_id field is correct on all processors on AMD platforms

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
_____64_model_name :_AMD_Opteron(TM)_Processor_6272

and the functionality is correct on an Intel box:

[thetango@prarit2]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
____144_model_name      :_Intel(R)_Xeon(R)_CPU_E7-8890_v3_@_2.50GHz
Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc Brian Gerst <[email protected]>
---
 arch/x86/kernel/cpu/common.c |   17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/common.c +4 -13
index a62cf04..9405c1e 100644
@@ -419,7 +419,6 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
-	char *p, *q;
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	c->x86_model_id[48] = 0;
 
 	/*
-	 * Intel chips right-justify this string for some dumb reason;
-	 * undo that brain damage:
+	 * Remove leading whitespace on Intel processors and trailing
+	 * whitespace on AMD processors.
 	 */
-	p = q = &c->x86_model_id[0];
-	while (*p == ' ')
-		p++;
-	if (p != q) {
-		while (*p)
-			*q++ = *p++;
-		while (q <= &c->x86_model_id[48])
-			*q++ = '\0';	/* Zero-pad the rest */
-	}
+	strlcpy(c->x86_model_id, strim(c->x86_model_id), 48);
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
@@ -1122,7 +1113,7 @@ void print_cpu_info(struct cpuinfo_x86 *c)
 		printk(KERN_CONT "%s ", vendor);
 
 	if (c->x86_model_id[0])
-		printk(KERN_CONT "%s", strim(c->x86_model_id));
+		printk(KERN_CONT "%s", c->x86_model_id);
 	else
 		printk(KERN_CONT "%d86", c->x86);
 
Signature · 1 line
1.7.9.3
maintainer Applied
#414 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 49 lines · Prarit Bhargava

When comparing 'model name' fields in /proc/cpuinfo it was noticed that a simple test comparing the model name fields was failing. After some quick investigation it was noticed that the model name fields were actually different -- processor 0's model name field had trailing white space removed, while the other processors did not.

Another way of seeing this behaviour is to convert spaces into underscores in the output of /proc/cpuinfo,

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

which shows two different model name fields even though they should be the same.

This occurs because the kernel calls strim() on cpu 0's x86_model_id field to output a pretty message to the console in print_cpu_info(), and as a result truncates the whitespace at the end of the x86_model_id field.

The x86_model_id field should be the same for the same processors. This patch uses string functions to remove both leading and trailing whitespace in the x86_model_id field. As a result the print_cpu_info() output looks like

smpboot: CPU0: AMD Opteron(TM) Processor 6272 (fam: 15, model: 01, stepping: 02)

and the x86_model_id field is correct on all processors on AMD platforms

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
_____64_model_name :_AMD_Opteron(TM)_Processor_6272

and the functionality is correct on an Intel box:

[thetango@prarit2]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
____144_model_name      :_Intel(R)_Xeon(R)_CPU_E7-8890_v3_@_2.50GHz
Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc Brian Gerst <[email protected]>
Quoted 3 lines
---
 arch/x86/kernel/cpu/common.c |   17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

Applied, thanks.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#415 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

In reply to Prarit Bhargava
Quoted 75 lines · Prarit Bhargava

When comparing 'model name' fields in /proc/cpuinfo it was noticed that a simple test comparing the model name fields was failing. After some quick investigation it was noticed that the model name fields were actually different -- processor 0's model name field had trailing white space removed, while the other processors did not.

Another way of seeing this behaviour is to convert spaces into underscores in the output of /proc/cpuinfo,

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

which shows two different model name fields even though they should be the same.

This occurs because the kernel calls strim() on cpu 0's x86_model_id field to output a pretty message to the console in print_cpu_info(), and as a result truncates the whitespace at the end of the x86_model_id field.

The x86_model_id field should be the same for the same processors. This patch uses string functions to remove both leading and trailing whitespace in the x86_model_id field. As a result the print_cpu_info() output looks like

smpboot: CPU0: AMD Opteron(TM) Processor 6272 (fam: 15, model: 01, stepping: 02)

and the x86_model_id field is correct on all processors on AMD platforms

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
_____64_model_name :_AMD_Opteron(TM)_Processor_6272

and the functionality is correct on an Intel box:

[thetango@prarit2]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
____144_model_name      :_Intel(R)_Xeon(R)_CPU_E7-8890_v3_@_2.50GHz
Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc Brian Gerst <[email protected]>
---
 arch/x86/kernel/cpu/common.c |   17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/common.c +2 -4
index a62cf04..9405c1e 100644
@@ -419,7 +419,6 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
        unsigned int *v;
-       char *p, *q;
 
        if (c->extended_cpuid_level < 0x80000004)
                return;
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
        c->x86_model_id[48] = 0;
 
        /*
-        * Intel chips right-justify this string for some dumb reason;
-        * undo that brain damage:
+        * Remove leading whitespace on Intel processors and trailing
+        * whitespace on AMD processors.
         */
-       p = q = &c->x86_model_id[0];

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c) · line 437

Quoted 10 lines
arch/x86/kernel/cpu/common.c +1 -8
-       while (*p == ' ')
-               p++;
-       if (p != q) {
-               while (*p)
-                       *q++ = *p++;
-               while (q <= &c->x86_model_id[48])
-                       *q++ = '\0';    /* Zero-pad the rest */
-       }
+       strlcpy(c->x86_model_id, strim(c->x86_model_id), 48);
 }

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap. I would instead allocate a temp buffer on the stack:

    unsigned char model_id[49];
    v = (unsigned int *)model_id;
   ...
    strlcpy(c->x86_model_id, strim(model_id), 48);

--
Brian Gerst

maintainer
#416 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 2 lines · Brian Gerst

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap.

Why?

AFAICT, strlcpy() calls memcpy() and memcpy should handle overlapping buffers just fine.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#417 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 9 lines · Borislav Petkov
Quoted 2 lines · Brian Gerst

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap.

Why?

AFAICT, strlcpy() calls memcpy() and memcpy should handle overlapping buffers just fine.

Are you thinking of memmove?

--Andy

maintainer
#418 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 6 lines · Andy Lutomirski
Quoted 5 lines · Borislav Petkov
Quoted 2 lines · Brian Gerst

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap.

Quoted 6 lines
Quoted 4 lines

Why?

AFAICT, strlcpy() calls memcpy() and memcpy should handle overlapping buffers just fine.

Are you thinking of memmove?

I guess I'm trying to find out why don't we have a BIG FAT WARNING over memcpy saying not to use it with overlapping buffers and larger than byte sizes. Or maybe this is something everyone, except me, just knows and that's a "Doh, Boris, of course!".

Btw, can we still avoid using the temporary buffer and use strncpy() instead? AFAICT, that does byte copies, from looking at the asm.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#419 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 14 lines · Borislav Petkov
Quoted 6 lines · Andy Lutomirski
Quoted 5 lines · Borislav Petkov
Quoted 2 lines · Brian Gerst

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap.

Quoted 6 lines
Quoted 4 lines

Why?

AFAICT, strlcpy() calls memcpy() and memcpy should handle overlapping buffers just fine.

Are you thinking of memmove?

Quoted 7 lines

I guess I'm trying to find out why don't we have a BIG FAT WARNING over memcpy saying not to use it with overlapping buffers and larger than byte sizes. Or maybe this is something everyone, except me, just knows and that's a "Doh, Boris, of course!".

Btw, can we still avoid using the temporary buffer and use strncpy() instead? AFAICT, that does byte copies, from looking at the asm.

It's not just chunk size; it's the direction. If the dest starts after the source but overlaps it and you copy forwards, then you can clobber the end of the source before you read it. memmove is specifically intended to avoid this.

Would it be possible to just use memmove directly?

--Andy

#420 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 9 lines · Andy Lutomirski
Quoted 8 lines · Borislav Petkov
Quoted 7 lines · Andy Lutomirski
Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Brian Gerst

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap.

Why?

I think this is traditionally handled by specifying that the strcpy strings may not overlap, so the suggested

+ strlcpy(c->x86_model_id, strim(c->x86_model_id), 48);

isn't good code.

A temporary intermediate buffer is required.

#421 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 16 lines · Joe Perches
Quoted 9 lines · Andy Lutomirski
Quoted 8 lines · Borislav Petkov
Quoted 7 lines · Andy Lutomirski
Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Brian Gerst

Using strlcpy in this manner could fail if it does larger than byte copies and they overlap.

Why?

I think this is traditionally handled by specifying that the strcpy strings may not overlap, so the suggested

(quoted diff) +1 -0
+	strlcpy(c->x86_model_id, strim(c->x86_model_id), 48);
Quoted 3 lines

isn't good code.

A temporary intermediate buffer is required.

Or memmove. (duh)

maintainer
#422 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

In reply to Andy Lutomirski
Quoted 3 lines · Andy Lutomirski

It's not just chunk size; it's the direction. If the dest starts after the source but overlaps it and you copy forwards, then you can clobber the end of the source before you read it. memmove is

Some things should simply be done solely in userspace :-)

Quoted 3 lines

specifically intended to avoid this.

Would it be possible to just use memmove directly?

Yeah.

Prarit, care to send a v2?

Thanks.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#423 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 7 lines · Borislav Petkov
Quoted 3 lines · Andy Lutomirski

It's not just chunk size; it's the direction. If the dest starts after the source but overlaps it and you copy forwards, then you can clobber the end of the source before you read it. memmove is

Some things should simply be done solely in userspace :-)

Quoted 7 lines
Quoted 3 lines

specifically intended to avoid this.

Would it be possible to just use memmove directly?

Yeah.

Prarit, care to send a v2?

Yep, I can do that. It'll have to wait until I get into the office in the morning so I can retest.

P.

Quoted 3 lines

Thanks.

#424 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

In reply to Borislav Petkov
Quoted 6 lines · Borislav Petkov

I guess I'm trying to find out why don't we have a BIG FAT WARNING over memcpy saying not to use it with overlapping buffers and larger than byte sizes. Or maybe this is something everyone, except me, just knows and that's a "Doh, Boris, of course!".

It kind of is, and doesn't just apply to kernel programming. In C99+ the memcpy() prototype has "restrict" in it to denote that memcpy() buffers have to be non-overlapping.

-hpa

#425 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

In reply to Prarit Bhargava
Quoted 2 lines · Prarit Bhargava
 arch/x86/kernel/cpu/common.c |   17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

So I saw this title:

[PATCH] x86, cpuinfo x86_model_id whitespace cleanup

... and in an early morning deconcentrated state was skipped the changelog and was looking for a whitespace coding style cleanup:

Quoted 10 lines
arch/x86/kernel/cpu/common.c +2 -3
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	c->x86_model_id[48] = 0;
 
 	/*
-	 * Intel chips right-justify this string for some dumb reason;
-	 * undo that brain damage:
+	 * Remove leading whitespace on Intel processors and trailing
+	 * whitespace on AMD processors.
 	 */
-	p = q = &c->x86_model_id[0];

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c) · line 437

Quoted 10 lines
arch/x86/kernel/cpu/common.c +1 -8
-	while (*p == ' ')
-		p++;
-	if (p != q) {
-		while (*p)
-			*q++ = *p++;
-		while (q <= &c->x86_model_id[48])
-			*q++ = '\0';	/* Zero-pad the rest */
-	}
+	strlcpy(c->x86_model_id, strim(c->x86_model_id), 48);
 }

Which this clearly isnt!

Fortunately before complaining about that I read the changelog as well, and realized that the 'whitespace cleanup' is done to /proc/cpuinfo ABI output.

Could you please make the title less ambiguous, so that sleepy kernel developers get the right idea what the patch looks like, from the title alone? Git shortlogs will vastly improve as well.

Something like:

[PATCH] x86/cpu: Strip leading and trailing spaces from the /proc/cpuinfo CPU model field

... or so would work very well for me!

Thanks,

Ingo

#426 lore raw

Re: [PATCH] x86, cpuinfo x86_model_id whitespace cleanup

Quoted 44 lines · Ingo Molnar
Quoted 2 lines · Prarit Bhargava
 arch/x86/kernel/cpu/common.c |   17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

So I saw this title:

[PATCH] x86, cpuinfo x86_model_id whitespace cleanup

... and in an early morning deconcentrated state was skipped the changelog and was looking for a whitespace coding style cleanup:

Quoted 10 lines
arch/x86/kernel/cpu/common.c +2 -3
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	c->x86_model_id[48] = 0;
 
 	/*
-	 * Intel chips right-justify this string for some dumb reason;
-	 * undo that brain damage:
+	 * Remove leading whitespace on Intel processors and trailing
+	 * whitespace on AMD processors.
 	 */
-	p = q = &c->x86_model_id[0];

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c) · line 437

Quoted 10 lines
arch/x86/kernel/cpu/common.c +1 -8
-	while (*p == ' ')
-		p++;
-	if (p != q) {
-		while (*p)
-			*q++ = *p++;
-		while (q <= &c->x86_model_id[48])
-			*q++ = '\0';	/* Zero-pad the rest */
-	}
+	strlcpy(c->x86_model_id, strim(c->x86_model_id), 48);
 }

Which this clearly isnt!

Fortunately before complaining about that I read the changelog as well, and realized that the 'whitespace cleanup' is done to /proc/cpuinfo ABI output.

Could you please make the title less ambiguous, so that sleepy kernel developers get the right idea what the patch looks like, from the title alone? Git shortlogs will vastly improve as well.

Quoted 5 lines

Something like:

[PATCH] x86/cpu: Strip leading and trailing spaces from the /proc/cpuinfo CPU model field

... or so would work very well for me!

:) Sorry Ingo -- I'll definitely clean that up in the next version.

P.

Quoted 5 lines

Thanks,

Ingo

#427 lore raw

[tip:x86/cpu] x86/cpu: Trim model ID whitespace

In reply to Prarit Bhargava
x86/cpu: Trim model ID whitespace
Commit-ID:  ee098e1aed67715f0ce4651813d0c33ab3a56e0b
Gitweb:     http://git.kernel.org/tip/ee098e1aed67715f0ce4651813d0c33ab3a56e0b
Author:     Borislav Petkov <[email protected]>
AuthorDate: Mon, 1 Jun 2015 12:06:57 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 2 Jun 2015 10:38:11 +0200

x86/cpu: Trim model ID whitespace

We did try trimming whitespace surrounding the 'model name' field in /proc/cpuinfo since reportedly some userspace uses it in string comparisons and there were discrepancies:

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

However, there were issues with overlapping buffers, string sizes and non-byte-sized copies in the previous proposed solutions; see Link tags below for the whole farce.

So, instead of diddling with this more, let's simply extend what was there originally with trimming any present trailing whitespace. Final result is really simple and obvious.

Testing with the most insane model IDs qemu can generate, looks good:

.model_id = " My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = "My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " My funny model ID CPU",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " ",
______4_model_name :__

.model_id = "",
______4_model_name :_15/02

Cc Andy Lutomirski <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/kernel/cpu/common.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/common.c +17 -5
index 41a8e9c..351197c 100644
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -419,6 +420,7 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	char *p, *q, *s;
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -429,11 +431,21 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
 
-	/*
-	 * Remove leading whitespace on Intel processors and trailing
-	 * whitespace on AMD processors.
-	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	/* Trim whitespace */
+	p = q = s = &c->x86_model_id[0];
+
+	while (*p == ' ')
+		p++;
+
+	while (*p) {
+		/* Note the last non-whitespace index */
+		if (!isspace(*p))
+			s = q;
+
+		*q++ = *p++;
+	}
+
+	*(s + 1) = '\0';
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
#428 lore raw

PATCH 1/1 mce: fix fail to set 'monarchtimeout' via boot option

I use "mce=1,10000000" in cmdline to change the monarch timeout, but it does not work.

The cause is that get_option() has parsed the ',' already, we need not to check the ',' again.

--
get_option(): read an int from an option string;
if available accept a subsequent comma as well.

Return values:
0 - no int in string
1 - int found, no subsequent comma
2 - int found including a subsequent comma
3 - hyphen found to denote a range

---
 arch/x86/kernel/cpu/mcheck/mce.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +1 -4
index 2a2bb91..46ca8e7 100644
@@ -2020,11 +2020,8 @@ static int __init mcheck_enable(char *str)
 	else if (!strcmp(str, "bios_cmci_threshold"))
 		cfg->bios_cmci_threshold = true;
 	else if (isdigit(str[0])) {
-		get_option(&str, &(cfg->tolerant));
-		if (*str == ',') {
-			++str;
+		if (get_option(&str, &(cfg->tolerant) == 2)
 			get_option(&str, &(cfg->monarch_timeout));
-		}
 	} else {
 		pr_info("mce argument %s ignored. Please use /sys\n", str);
 		return 0;
Signature · 1 line
1.8.3.1
maintainer
#429 lore raw

Re: [PATCH] mce: fix fail to set 'monarchtimeout' via boot option

Quoted 10 lines · Xie XiuQi

I use "mce=1,10000000" in cmdline to change the monarch timeout, but it does not work.

The cause is that get_option() has parsed the ',' already, we need not to check the ',' again.

--
get_option(): read an int from an option string;
if available accept a subsequent comma as well.

Quoted 7 lines

Return values:
0 - no int in string
1 - int found, no subsequent comma
2 - int found including a subsequent comma
3 - hyphen found to denote a range

Cc <[email protected]> # 2.6.32+

I don't think that's a serious enough a bug to justify the stable tag.

Quoted 10 lines
---
 arch/x86/kernel/cpu/mcheck/mce.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +0 -0
index 2a2bb91..46ca8e7 100644

arch/x86/kernel/cpu/mcheck/mce.c static int __init mcheck_enable(char *str) · line 2023

Quoted 7 lines
arch/x86/kernel/cpu/mcheck/mce.c +1 -3
@@ -2020,11 +2020,8 @@ static int __init mcheck_enable(char *str)
 	else if (!strcmp(str, "bios_cmci_threshold"))
 		cfg->bios_cmci_threshold = true;
 	else if (isdigit(str[0])) {
-		get_option(&str, &(cfg->tolerant));
-		if (*str == ',') {
-			++str;
+		if (get_option(&str, &(cfg->tolerant) == 2)

This patch wasn't build-tested, right:

arch/x86/kernel/cpu/mcheck/mce.c: In function ‘mcheck_enable’:
arch/x86/kernel/cpu/mcheck/mce.c:1993:41: warning: comparison between pointer and integer
if (get_option(&str, &(cfg->tolerant) == 2)

                                         ^
arch/x86/kernel/cpu/mcheck/mce.c:1993:24: warning: passing argument 2 of ‘get_option’ makes pointer from integer without a cast
   if (get_option(&str, &(cfg->tolerant) == 2)
                        ^
In file included from include/asm-generic/bug.h:13:0,
                 from ./arch/x86/include/asm/bug.h:35,
                 from include/linux/bug.h:4,
                 from include/linux/thread_info.h:11,
                 from arch/x86/kernel/cpu/mcheck/mce.c:13:
include/linux/kernel.h:420:12: note: expected ‘int *’ but argument is of type ‘int’
 extern int get_option(char **str, int *pint);
            ^
arch/x86/kernel/cpu/mcheck/mce.c:1994:4: error: expected ‘)’ before ‘get_option’
    get_option(&str, &(cfg->monarch_timeout));
    ^

arch/x86/kernel/cpu/mcheck/mce.c:1995:2: error: expected expression before ‘}’ token
} else {
^
make[4]: *** [arch/x86/kernel/cpu/mcheck/mce.o] Error 1
make[3]: *** [arch/x86/kernel/cpu/mcheck] Error 2
make[2]: *** [arch/x86/kernel/cpu] Error 2
make[1]: *** [arch/x86/kernel] Error 2
make: *** [arch/x86] Error 2
make: *** Waiting for unfinished jobs....

arch/x86/kernel/cpu/mcheck/mce.c static int __init mcheck_enable(char *str) · line 2027

Quoted 5 lines
arch/x86/kernel/cpu/mcheck/mce.c +0 -1
 			get_option(&str, &(cfg->monarch_timeout));
-		}
 	} else {
 		pr_info("mce argument %s ignored. Please use /sys\n", str);
 		return 0;

Anyway, I fixed it up and applied it.

Thanks.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#430 lore raw

Re: [PATCH] mce: fix fail to set 'monarchtimeout' via boot option

Quoted 23 lines · Borislav Petkov
Quoted 10 lines · Xie XiuQi

I use "mce=1,10000000" in cmdline to change the monarch timeout, but it does not work.

The cause is that get_option() has parsed the ',' already, we need not to check the ',' again.

--
get_option(): read an int from an option string;
if available accept a subsequent comma as well.

Quoted 7 lines

Return values:
0 - no int in string
1 - int found, no subsequent comma
2 - int found including a subsequent comma
3 - hyphen found to denote a range

Cc <[email protected]> # 2.6.32+

I don't think that's a serious enough a bug to justify the stable tag.

Quoted 2 lines

---

...

Quoted 3 lines
Quoted 1 line

return 0;

Anyway, I fixed it up and applied it.

Sorry, I will check carefully next time.

Thanks.

Quoted 3 lines

Thanks.

maintainer
#431 lore raw

cover tip queue 2015-05-26

From: Borislav Petkov <[email protected]>

Hi Ingo,

some more stuff this week. None of it is urgent material, the bigger chunk is MTRR/PAT cleanups.

Borislav Petkov (3):
x86/documentation: Move kernel-stacks doc one level up x86/documentation: Remove STACKFAULT_STACK bulletpoint x86/documentation: Adapt Ingo's explanation on printing backtraces

Huang Rui (1):
x86/process: Drop repeated word from comment

Luis R. Rodriguez (6):
x86/mm/pat: Convert to pr_* usage
x86: Document Write Combining MTRR type effects on PAT / non-PAT pages x86/mtrr: Avoid ifdeffery with phys_wc_to_mtrr_index() x86/mtrr: Generalize runtime disabling of MTRRs x86/mm/pat: Wrap pat_enabled
x86/mm/pat: Export pat_enabled()

Prarit Bhargava (1):
x86/cpu: Strip any /proc/cpuinfo model name field whitespace

Toshi Kani (6):
x86/kconfig: Simplify conditions for HAVE_ARCH_HUGE_VMAP x86/mtrr: Fix MTRR lookup to handle an inclusive entry x86/mtrr: Fix MTRR state checks in mtrr_type_lookup() x86/mtrr: Use symbolic define as a retval for disabled MTRRs x86/mtrr: Clean up mtrr_type_lookup()
x86/mm: Enhance MTRR checks in kernel mapping helpers

Xie XiuQi (1):
x86/mce: Fix monarch timeout setting through the mce= cmdline option

maintainer
#432 lore raw

PATCH 1/18 x86/kconfig: Simplify conditions for HAVE_ARCH_HUGE_VMAP

From: Toshi Kani <[email protected]>

Simplify the conditions selecting HAVE_ARCH_HUGE_VMAP since X86_PAE depends on X86_32 already.

---
 arch/x86/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/Kconfig +1 -1
index 226d5696e1d1..4eb0b0ffae85 100644
@@ -100,7 +100,7 @@ config X86
 	select IRQ_FORCED_THREADING
 	select HAVE_BPF_JIT if X86_64
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
-	select HAVE_ARCH_HUGE_VMAP if X86_64 || (X86_32 && X86_PAE)
+	select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE
 	select ARCH_HAS_SG_CHAIN
 	select CLKEVT_I8253
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
Signature · 1 line
1.9.0.258.g00eda23
#433 lore raw

[tip:x86/mm] x86/mm/kconfig: Simplify conditions for HAVE_ARCH_HUGE_VMAP

x86/mm/kconfig: Simplify conditions for HAVE_ARCH_HUGE_VMAP
Commit-ID:  10455f64aff0d715dcdfb09b02393df168fe267e
Gitweb:     http://git.kernel.org/tip/10455f64aff0d715dcdfb09b02393df168fe267e
Author:     Toshi Kani <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:04 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:55 +0200

x86/mm/kconfig: Simplify conditions for HAVE_ARCH_HUGE_VMAP

Simplify the conditions selecting HAVE_ARCH_HUGE_VMAP since X86_PAE depends on X86_32 already.

---
 arch/x86/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/Kconfig +1 -1
index 226d569..4eb0b0f 100644
@@ -100,7 +100,7 @@ config X86
 	select IRQ_FORCED_THREADING
 	select HAVE_BPF_JIT if X86_64
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
-	select HAVE_ARCH_HUGE_VMAP if X86_64 || (X86_32 && X86_PAE)
+	select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE
 	select ARCH_HAS_SG_CHAIN
 	select CLKEVT_I8253
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#434 lore raw

PATCH 2/18 x86/mtrr: Fix MTRR lookup to handle an inclusive entry

In reply to Borislav Petkov

From: Toshi Kani <[email protected]>

When an MTRR entry is inclusive to a requested range, i.e. the start and end of the request are not within the MTRR entry range but the range contains the MTRR entry entirely:

range_start ... [mtrr_start ... mtrr_end] ... range_end

__mtrr_type_lookup() ignores such a case because both start_state and end_state are set to zero.

This bug can cause the following issues:

1) reserve_memtype() tracks an effective memory type in case a request type is WB (ex. /dev/mem blindly uses WB). Missing to track with its effective type causes a subsequent request to map the same range with the effective type to fail.

2) pud_set_huge() and pmd_set_huge() check if a requested range has any overlap with MTRRs. Missing to detect an overlap may cause a performance penalty or undefined behavior.

This patch fixes the bug by adding a new flag, 'inclusive', to detect the inclusive case. This case is then handled in the same way as end_state:1 since the first region is the same. With this fix, __mtrr_type_lookup() handles the inclusive case properly.

---
 arch/x86/kernel/cpu/mtrr/generic.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/mtrr/generic.c +18 -10
index 5b239679cfc9..e202d26f64a2 100644
@@ -154,7 +154,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 
 	prev_match = 0xFF;
 	for (i = 0; i < num_var_ranges; ++i) {
-		unsigned short start_state, end_state;
+		unsigned short start_state, end_state, inclusive;
 
 		if (!(mtrr_state.var_ranges[i].mask_lo & (1 << 11)))
 			continue;
@@ -166,19 +166,27 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 
 		start_state = ((start & mask) == (base & mask));
 		end_state = ((end & mask) == (base & mask));
+		inclusive = ((start < base) && (end > base));
 
-		if (start_state != end_state) {
+		if ((start_state != end_state) || inclusive) {
 			/*
 			 * We have start:end spanning across an MTRR.
-			 * We split the region into
-			 * either
-			 * (start:mtrr_end) (mtrr_end:end)
-			 * or
-			 * (start:mtrr_start) (mtrr_start:end)
+			 * We split the region into either
+			 *
+			 * - start_state:1
+			 * (start:mtrr_end)(mtrr_end:end)
+			 * - end_state:1
+			 * (start:mtrr_start)(mtrr_start:end)
+			 * - inclusive:1
+			 * (start:mtrr_start)(mtrr_start:mtrr_end)(mtrr_end:end)
+			 *
 			 * depending on kind of overlap.
-			 * Return the type for first region and a pointer to
-			 * the start of second region so that caller will
-			 * lookup again on the second region.
+			 *
+			 * Return the type of the first region and a pointer
+			 * to the start of next region so that caller will be
+			 * advised to lookup again after having adjusted start
+			 * and end.
+			 *
 			 * Note: This way we handle multiple overlaps as well.
 			 */
 			if (start_state)
Signature · 1 line
1.9.0.258.g00eda23
#435 lore raw

[tip:x86/mm] x86/mm/mtrr: Fix MTRR lookup to handle an inclusive entry

x86/mm/mtrr: Fix MTRR lookup to handle an inclusive entry
Commit-ID:  7f0431e3dc8953f41e9433581c1fdd7ee45860b0
Gitweb:     http://git.kernel.org/tip/7f0431e3dc8953f41e9433581c1fdd7ee45860b0
Author:     Toshi Kani <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:05 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:56 +0200

x86/mm/mtrr: Fix MTRR lookup to handle an inclusive entry

When an MTRR entry is inclusive to a requested range, i.e. the start and end of the request are not within the MTRR entry range but the range contains the MTRR entry entirely:

range_start ... [mtrr_start ... mtrr_end] ... range_end

__mtrr_type_lookup() ignores such a case because both start_state and end_state are set to zero.

This bug can cause the following issues:

1) reserve_memtype() tracks an effective memory type in case a request type is WB (ex. /dev/mem blindly uses WB). Missing to track with its effective type causes a subsequent request to map the same range with the effective type to fail.

2) pud_set_huge() and pmd_set_huge() check if a requested range has any overlap with MTRRs. Missing to detect an overlap may cause a performance penalty or undefined behavior.

This patch fixes the bug by adding a new flag, 'inclusive', to detect the inclusive case. This case is then handled in the same way as end_state:1 since the first region is the same. With this fix, __mtrr_type_lookup() handles the inclusive case properly.

---
 arch/x86/kernel/cpu/mtrr/generic.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/mtrr/generic.c +18 -10
index 5b23967..e202d26 100644
@@ -154,7 +154,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 
 	prev_match = 0xFF;
 	for (i = 0; i < num_var_ranges; ++i) {
-		unsigned short start_state, end_state;
+		unsigned short start_state, end_state, inclusive;
 
 		if (!(mtrr_state.var_ranges[i].mask_lo & (1 << 11)))
 			continue;
@@ -166,19 +166,27 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 
 		start_state = ((start & mask) == (base & mask));
 		end_state = ((end & mask) == (base & mask));
+		inclusive = ((start < base) && (end > base));
 
-		if (start_state != end_state) {
+		if ((start_state != end_state) || inclusive) {
 			/*
 			 * We have start:end spanning across an MTRR.
-			 * We split the region into
-			 * either
-			 * (start:mtrr_end) (mtrr_end:end)
-			 * or
-			 * (start:mtrr_start) (mtrr_start:end)
+			 * We split the region into either
+			 *
+			 * - start_state:1
+			 * (start:mtrr_end)(mtrr_end:end)
+			 * - end_state:1
+			 * (start:mtrr_start)(mtrr_start:end)
+			 * - inclusive:1
+			 * (start:mtrr_start)(mtrr_start:mtrr_end)(mtrr_end:end)
+			 *
 			 * depending on kind of overlap.
-			 * Return the type for first region and a pointer to
-			 * the start of second region so that caller will
-			 * lookup again on the second region.
+			 *
+			 * Return the type of the first region and a pointer
+			 * to the start of next region so that caller will be
+			 * advised to lookup again after having adjusted start
+			 * and end.
+			 *
 			 * Note: This way we handle multiple overlaps as well.
 			 */
 			if (start_state)

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#436 lore raw

PATCH 3/18 x86/mtrr: Fix MTRR state checks in mtrr_type_lookup()

In reply to Borislav Petkov

From: Toshi Kani <[email protected]>

'mtrr_state.enabled' contains the FE (fixed MTRRs enabled) and E (MTRRs enabled) flags in MSR_MTRRdefType. Intel SDM, section 11.11.2.1, defines these flags as follows:

- All MTRRs are disabled when the E flag is clear. The FE flag has no affect when the E flag is clear.
- The default type is enabled when the E flag is set.
- MTRR variable ranges are enabled when the E flag is set.
- MTRR fixed ranges are enabled when both E and FE flags are set.

MTRR state checks in __mtrr_type_lookup() do not match with SDM.

Hence, this patch makes the following changes:
- The current code detects MTRRs disabled when both E and FE flags are clear in mtrr_state.enabled. Fix to detect MTRRs disabled when the E flag is clear.
- The current code does not check if the FE bit is set in mtrr_state.enabled when looking at the fixed entries. Fix to check the FE flag.
- The current code returns the default type when the E flag is clear in mtrr_state.enabled. However, the default type is UC when the E flag is clear. Remove the code as this case is handled as MTRR disabled with the 1st change.

In addition, this patch defines the E and FE flags in mtrr_state.enabled as follows.
- FE flag: MTRR_STATE_MTRR_FIXED_ENABLED
- E flag: MTRR_STATE_MTRR_ENABLED

print_mtrr_state() and x86_get_mtrr_mem_range() are also updated accordingly.

---
 arch/x86/include/asm/mtrr.h        |  4 ++++
 arch/x86/kernel/cpu/mtrr/cleanup.c |  3 ++-
 arch/x86/kernel/cpu/mtrr/generic.c | 15 ++++++++-------
 3 files changed, 14 insertions(+), 8 deletions(-)
arch/x86/include/asm/mtrr.h +4 -0
index f768f6298419..ef927948657c 100644
@@ -127,4 +127,8 @@ struct mtrr_gentry32 {
 				 _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry32)
 #endif /* CONFIG_COMPAT */
 
+/* Bit fields for enabled in struct mtrr_state_type */
+#define MTRR_STATE_MTRR_FIXED_ENABLED	0x01
+#define MTRR_STATE_MTRR_ENABLED		0x02
+
 #endif /* _ASM_X86_MTRR_H */
arch/x86/kernel/cpu/mtrr/cleanup.c +2 -1
index 5f90b85ff22e..70d7c93f4550 100644
@@ -98,7 +98,8 @@ x86_get_mtrr_mem_range(struct range *range, int nr_range,
 			continue;
 		base = range_state[i].base_pfn;
 		if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
-		    (mtrr_state.enabled & 1)) {
+		    (mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
+		    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
 			/* Var MTRR contains UC entry below 1M? Skip it: */
 			printk(BIOS_BUG_MSG, i);
 			if (base + size <= (1<<(20-PAGE_SHIFT)))
arch/x86/kernel/cpu/mtrr/generic.c +8 -7
index e202d26f64a2..b0599dbb899a 100644
@@ -119,14 +119,16 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 	if (!mtrr_state_set)
 		return 0xFF;
 
-	if (!mtrr_state.enabled)
+	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
 		return 0xFF;
 
 	/* Make end inclusive end, instead of exclusive */
 	end--;
 
 	/* Look in fixed ranges. Just return the type as per start */
-	if (mtrr_state.have_fixed && (start < 0x100000)) {
+	if ((start < 0x100000) &&
+	    (mtrr_state.have_fixed) &&
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
 		int idx;
 
 		if (start < 0x80000) {
@@ -149,9 +151,6 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 	 * Look of multiple ranges matching this address and pick type
 	 * as per MTRR precedence
 	 */
-	if (!(mtrr_state.enabled & 2))
-		return mtrr_state.def_type;
-
 	prev_match = 0xFF;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
@@ -355,7 +354,9 @@ static void __init print_mtrr_state(void)
 		 mtrr_attrib_to_str(mtrr_state.def_type));
 	if (mtrr_state.have_fixed) {
 		pr_debug("MTRR fixed ranges %sabled:\n",
-			 mtrr_state.enabled & 1 ? "en" : "dis");
+			((mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
+			 (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) ?
+			 "en" : "dis");
 		print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
 		for (i = 0; i < 2; ++i)
 			print_fixed(0x80000 + i * 0x20000, 0x04000,
@@ -368,7 +369,7 @@ static void __init print_mtrr_state(void)
 		print_fixed_last();
 	}
 	pr_debug("MTRR variable ranges %sabled:\n",
-		 mtrr_state.enabled & 2 ? "en" : "dis");
+		 mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED ? "en" : "dis");
 	high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4;
 
 	for (i = 0; i < num_var_ranges; ++i) {
Signature · 1 line
1.9.0.258.g00eda23
#437 lore raw

[tip:x86/mm] x86/mm/mtrr: Fix MTRR state checks in mtrr_type_lookup()

x86/mm/mtrr: Fix MTRR state checks in mtrr_type_lookup()
Commit-ID:  9b3aca620883fc06636737c82a4d024b22182281
Gitweb:     http://git.kernel.org/tip/9b3aca620883fc06636737c82a4d024b22182281
Author:     Toshi Kani <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:06 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:56 +0200

x86/mm/mtrr: Fix MTRR state checks in mtrr_type_lookup()

'mtrr_state.enabled' contains the FE (fixed MTRRs enabled) and E (MTRRs enabled) flags in MSR_MTRRdefType. Intel SDM, section 11.11.2.1, defines these flags as follows:

- All MTRRs are disabled when the E flag is clear. The FE flag has no affect when the E flag is clear.
- The default type is enabled when the E flag is set.
- MTRR variable ranges are enabled when the E flag is set.
- MTRR fixed ranges are enabled when both E and FE flags are set.

MTRR state checks in __mtrr_type_lookup() do not match with SDM.

Hence, this patch makes the following changes:
- The current code detects MTRRs disabled when both E and FE flags are clear in mtrr_state.enabled. Fix to detect MTRRs disabled when the E flag is clear.
- The current code does not check if the FE bit is set in mtrr_state.enabled when looking at the fixed entries. Fix to check the FE flag.
- The current code returns the default type when the E flag is clear in mtrr_state.enabled. However, the default type is UC when the E flag is clear. Remove the code as this case is handled as MTRR disabled with the 1st change.

In addition, this patch defines the E and FE flags in mtrr_state.enabled as follows.
- FE flag: MTRR_STATE_MTRR_FIXED_ENABLED
- E flag: MTRR_STATE_MTRR_ENABLED

print_mtrr_state() and x86_get_mtrr_mem_range() are also updated accordingly.

---
 arch/x86/include/asm/mtrr.h        |  4 ++++
 arch/x86/kernel/cpu/mtrr/cleanup.c |  3 ++-
 arch/x86/kernel/cpu/mtrr/generic.c | 15 ++++++++-------
 3 files changed, 14 insertions(+), 8 deletions(-)
arch/x86/include/asm/mtrr.h +4 -0
index f768f62..ef92794 100644
@@ -127,4 +127,8 @@ struct mtrr_gentry32 {
 				 _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry32)
 #endif /* CONFIG_COMPAT */
 
+/* Bit fields for enabled in struct mtrr_state_type */
+#define MTRR_STATE_MTRR_FIXED_ENABLED	0x01
+#define MTRR_STATE_MTRR_ENABLED		0x02
+
 #endif /* _ASM_X86_MTRR_H */
arch/x86/kernel/cpu/mtrr/cleanup.c +2 -1
index 5f90b85..70d7c93 100644
@@ -98,7 +98,8 @@ x86_get_mtrr_mem_range(struct range *range, int nr_range,
 			continue;
 		base = range_state[i].base_pfn;
 		if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
-		    (mtrr_state.enabled & 1)) {
+		    (mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
+		    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
 			/* Var MTRR contains UC entry below 1M? Skip it: */
 			printk(BIOS_BUG_MSG, i);
 			if (base + size <= (1<<(20-PAGE_SHIFT)))
arch/x86/kernel/cpu/mtrr/generic.c +8 -7
index e202d26..b0599db 100644
@@ -119,14 +119,16 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 	if (!mtrr_state_set)
 		return 0xFF;
 
-	if (!mtrr_state.enabled)
+	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
 		return 0xFF;
 
 	/* Make end inclusive end, instead of exclusive */
 	end--;
 
 	/* Look in fixed ranges. Just return the type as per start */
-	if (mtrr_state.have_fixed && (start < 0x100000)) {
+	if ((start < 0x100000) &&
+	    (mtrr_state.have_fixed) &&
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
 		int idx;
 
 		if (start < 0x80000) {
@@ -149,9 +151,6 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 	 * Look of multiple ranges matching this address and pick type
 	 * as per MTRR precedence
 	 */
-	if (!(mtrr_state.enabled & 2))
-		return mtrr_state.def_type;
-
 	prev_match = 0xFF;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
@@ -355,7 +354,9 @@ static void __init print_mtrr_state(void)
 		 mtrr_attrib_to_str(mtrr_state.def_type));
 	if (mtrr_state.have_fixed) {
 		pr_debug("MTRR fixed ranges %sabled:\n",
-			 mtrr_state.enabled & 1 ? "en" : "dis");
+			((mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
+			 (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) ?
+			 "en" : "dis");
 		print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
 		for (i = 0; i < 2; ++i)
 			print_fixed(0x80000 + i * 0x20000, 0x04000,
@@ -368,7 +369,7 @@ static void __init print_mtrr_state(void)
 		print_fixed_last();
 	}
 	pr_debug("MTRR variable ranges %sabled:\n",
-		 mtrr_state.enabled & 2 ? "en" : "dis");
+		 mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED ? "en" : "dis");
 	high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4;
 
 	for (i = 0; i < num_var_ranges; ++i) {

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#438 lore raw

PATCH 4/18 x86/mtrr: Use symbolic define as a retval for disabled MTRRs

In reply to Borislav Petkov

From: Toshi Kani <[email protected]>

mtrr_type_lookup() returns verbatim 0xFF when MTRRs are disabled. This patch defines MTRR_TYPE_INVALID to clarify the meaning of this value, and documents its usage.

Document the return values of the kernel virtual address mapping helpers pud_set_huge(), pmd_set_huge, pud_clear_huge() and pmd_clear_huge().

There is no functional change in this patch.

---
 arch/x86/include/asm/mtrr.h        |  2 +-
 arch/x86/include/uapi/asm/mtrr.h   |  8 +++++++-
 arch/x86/kernel/cpu/mtrr/generic.c | 14 ++++++-------
 arch/x86/mm/pgtable.c              | 42 +++++++++++++++++++++++++++++---------
 4 files changed, 47 insertions(+), 19 deletions(-)
arch/x86/include/asm/mtrr.h +1 -1
index ef927948657c..bb03a547c1ab 100644
@@ -55,7 +55,7 @@ static inline u8 mtrr_type_lookup(u64 addr, u64 end)
 	/*
 	 * Return no-MTRRs:
 	 */
-	return 0xff;
+	return MTRR_TYPE_INVALID;
 }
 #define mtrr_save_fixed_ranges(arg) do {} while (0)
 #define mtrr_save_state() do {} while (0)
arch/x86/include/uapi/asm/mtrr.h +7 -1
index d0acb658c8f4..7528dcf59691 100644
@@ -103,7 +103,7 @@ struct mtrr_state_type {
 #define MTRRIOC_GET_PAGE_ENTRY   _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry)
 #define MTRRIOC_KILL_PAGE_ENTRY  _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry)
 
-/*  These are the region types  */
+/* MTRR memory types, which are defined in SDM */
 #define MTRR_TYPE_UNCACHABLE 0
 #define MTRR_TYPE_WRCOMB     1
 /*#define MTRR_TYPE_         2*/
@@ -113,5 +113,11 @@ struct mtrr_state_type {
 #define MTRR_TYPE_WRBACK     6
 #define MTRR_NUM_TYPES       7
 
+/*
+ * Invalid MTRR memory type.  mtrr_type_lookup() returns this value when
+ * MTRRs are disabled.  Note, this value is allocated from the reserved
+ * values (0x7-0xff) of the MTRR memory types.
+ */
+#define MTRR_TYPE_INVALID    0xff
 
 #endif /* _UAPI_ASM_X86_MTRR_H */
arch/x86/kernel/cpu/mtrr/generic.c +7 -7
index b0599dbb899a..7b1491c6232d 100644
@@ -104,7 +104,7 @@ static int check_type_overlap(u8 *prev, u8 *curr)
 
 /*
  * Error/Semi-error returns:
- * 0xFF - when MTRR is not enabled
+ * MTRR_TYPE_INVALID - when MTRR is not enabled
  * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
  *		corresponds only to [start:*partial_end].
  *		Caller has to lookup again for [*partial_end:end].
@@ -117,10 +117,10 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 
 	*repeat = 0;
 	if (!mtrr_state_set)
-		return 0xFF;
+		return MTRR_TYPE_INVALID;
 
 	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
-		return 0xFF;
+		return MTRR_TYPE_INVALID;
 
 	/* Make end inclusive end, instead of exclusive */
 	end--;
@@ -151,7 +151,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 	 * Look of multiple ranges matching this address and pick type
 	 * as per MTRR precedence
 	 */
-	prev_match = 0xFF;
+	prev_match = MTRR_TYPE_INVALID;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
 
@@ -206,7 +206,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			continue;
 
 		curr_match = mtrr_state.var_ranges[i].base_lo & 0xff;
-		if (prev_match == 0xFF) {
+		if (prev_match == MTRR_TYPE_INVALID) {
 			prev_match = curr_match;
 			continue;
 		}
@@ -220,7 +220,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			return MTRR_TYPE_WRBACK;
 	}
 
-	if (prev_match != 0xFF)
+	if (prev_match != MTRR_TYPE_INVALID)
 		return prev_match;
 
 	return mtrr_state.def_type;
@@ -229,7 +229,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 /*
  * Returns the effective MTRR type for the region
  * Error return:
- * 0xFF - when MTRR is not enabled
+ * MTRR_TYPE_INVALID - when MTRR is not enabled
  */
 u8 mtrr_type_lookup(u64 start, u64 end)
 {
arch/x86/mm/pgtable.c +32 -10

76 lines not on this page · raw message

Signature · 1 line
1.9.0.258.g00eda23
#439 lore raw

[tip:x86/mm] x86/mm/mtrr: Use symbolic define as a retval for disabled MTRRs

x86/mm/mtrr: Use symbolic define as a retval for disabled MTRRs
Commit-ID:  3d3ca416d9b0784cfcf244eeeba1bcaf421bc64d
Gitweb:     http://git.kernel.org/tip/3d3ca416d9b0784cfcf244eeeba1bcaf421bc64d
Author:     Toshi Kani <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:07 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:57 +0200

x86/mm/mtrr: Use symbolic define as a retval for disabled MTRRs

mtrr_type_lookup() returns verbatim 0xFF when MTRRs are disabled. This patch defines MTRR_TYPE_INVALID to clarify the meaning of this value, and documents its usage.

Document the return values of the kernel virtual address mapping helpers pud_set_huge(), pmd_set_huge, pud_clear_huge() and pmd_clear_huge().

There is no functional change in this patch.

---
 arch/x86/include/asm/mtrr.h        |  2 +-
 arch/x86/include/uapi/asm/mtrr.h   |  8 +++++++-
 arch/x86/kernel/cpu/mtrr/generic.c | 14 ++++++-------
 arch/x86/mm/pgtable.c              | 42 +++++++++++++++++++++++++++++---------
 4 files changed, 47 insertions(+), 19 deletions(-)
arch/x86/include/asm/mtrr.h +1 -1
index ef92794..bb03a54 100644
@@ -55,7 +55,7 @@ static inline u8 mtrr_type_lookup(u64 addr, u64 end)
 	/*
 	 * Return no-MTRRs:
 	 */
-	return 0xff;
+	return MTRR_TYPE_INVALID;
 }
 #define mtrr_save_fixed_ranges(arg) do {} while (0)
 #define mtrr_save_state() do {} while (0)
arch/x86/include/uapi/asm/mtrr.h +7 -1
index d0acb65..7528dcf 100644
@@ -103,7 +103,7 @@ struct mtrr_state_type {
 #define MTRRIOC_GET_PAGE_ENTRY   _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry)
 #define MTRRIOC_KILL_PAGE_ENTRY  _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry)
 
-/*  These are the region types  */
+/* MTRR memory types, which are defined in SDM */
 #define MTRR_TYPE_UNCACHABLE 0
 #define MTRR_TYPE_WRCOMB     1
 /*#define MTRR_TYPE_         2*/
@@ -113,5 +113,11 @@ struct mtrr_state_type {
 #define MTRR_TYPE_WRBACK     6
 #define MTRR_NUM_TYPES       7
 
+/*
+ * Invalid MTRR memory type.  mtrr_type_lookup() returns this value when
+ * MTRRs are disabled.  Note, this value is allocated from the reserved
+ * values (0x7-0xff) of the MTRR memory types.
+ */
+#define MTRR_TYPE_INVALID    0xff
 
 #endif /* _UAPI_ASM_X86_MTRR_H */
arch/x86/kernel/cpu/mtrr/generic.c +7 -7
index b0599db..7b1491c 100644
@@ -104,7 +104,7 @@ static int check_type_overlap(u8 *prev, u8 *curr)
 
 /*
  * Error/Semi-error returns:
- * 0xFF - when MTRR is not enabled
+ * MTRR_TYPE_INVALID - when MTRR is not enabled
  * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
  *		corresponds only to [start:*partial_end].
  *		Caller has to lookup again for [*partial_end:end].
@@ -117,10 +117,10 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 
 	*repeat = 0;
 	if (!mtrr_state_set)
-		return 0xFF;
+		return MTRR_TYPE_INVALID;
 
 	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
-		return 0xFF;
+		return MTRR_TYPE_INVALID;
 
 	/* Make end inclusive end, instead of exclusive */
 	end--;
@@ -151,7 +151,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 	 * Look of multiple ranges matching this address and pick type
 	 * as per MTRR precedence
 	 */
-	prev_match = 0xFF;
+	prev_match = MTRR_TYPE_INVALID;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
 
@@ -206,7 +206,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			continue;
 
 		curr_match = mtrr_state.var_ranges[i].base_lo & 0xff;
-		if (prev_match == 0xFF) {
+		if (prev_match == MTRR_TYPE_INVALID) {
 			prev_match = curr_match;
 			continue;
 		}
@@ -220,7 +220,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			return MTRR_TYPE_WRBACK;
 	}
 
-	if (prev_match != 0xFF)
+	if (prev_match != MTRR_TYPE_INVALID)
 		return prev_match;
 
 	return mtrr_state.def_type;
@@ -229,7 +229,7 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 /*
  * Returns the effective MTRR type for the region
  * Error return:
- * 0xFF - when MTRR is not enabled
+ * MTRR_TYPE_INVALID - when MTRR is not enabled
  */
 u8 mtrr_type_lookup(u64 start, u64 end)
 {
arch/x86/mm/pgtable.c +32 -10

76 lines not on this page · raw message

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#440 lore raw

PATCH 5/18 x86/mtrr: Clean up mtrr_type_lookup()

In reply to Borislav Petkov

From: Toshi Kani <[email protected]>

MTRRs contain fixed and variable entries. mtrr_type_lookup() may repeatedly call __mtrr_type_lookup() to handle a request that overlaps with variable entries.

However, __mtrr_type_lookup() also handles the fixed entries, which do not have to be repeated. Therefore, this patch creates separate functions, mtrr_type_lookup_fixed() and mtrr_type_lookup_variable(), to handle the fixed and variable ranges respectively.

The patch also updates the function headers to clarify the return values and output argument. It updates comments to clarify that the repeating is necessary to handle overlaps with the default type, since overlaps with multiple entries alone can be handled without such repeating.

There is no functional change in this patch.

---
 arch/x86/kernel/cpu/mtrr/generic.c | 138 +++++++++++++++++++++++--------------
 1 file changed, 86 insertions(+), 52 deletions(-)
arch/x86/kernel/cpu/mtrr/generic.c +86 -52
index 7b1491c6232d..e51100c49eea 100644
@@ -102,55 +102,68 @@ static int check_type_overlap(u8 *prev, u8 *curr)
 	return 0;
 }
 
-/*
- * Error/Semi-error returns:
- * MTRR_TYPE_INVALID - when MTRR is not enabled
- * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
- *		corresponds only to [start:*partial_end].
- *		Caller has to lookup again for [*partial_end:end].
+/**
+ * mtrr_type_lookup_fixed - look up memory type in MTRR fixed entries
+ *
+ * Return the MTRR fixed memory type of 'start'.
+ *
+ * MTRR fixed entries are divided into the following ways:
+ *  0x00000 - 0x7FFFF : This range is divided into eight 64KB sub-ranges
+ *  0x80000 - 0xBFFFF : This range is divided into sixteen 16KB sub-ranges
+ *  0xC0000 - 0xFFFFF : This range is divided into sixty-four 4KB sub-ranges
+ *
+ * Return Values:
+ * MTRR_TYPE_(type)  - Matched memory type
+ * MTRR_TYPE_INVALID - Unmatched
+ */
+static u8 mtrr_type_lookup_fixed(u64 start, u64 end)
+{
+	int idx;
+
+	if (start >= 0x100000)
+		return MTRR_TYPE_INVALID;
+
+	/* 0x0 - 0x7FFFF */
+	if (start < 0x80000) {
+		idx = 0;
+		idx += (start >> 16);
+		return mtrr_state.fixed_ranges[idx];
+	/* 0x80000 - 0xBFFFF */
+	} else if (start < 0xC0000) {
+		idx = 1 * 8;
+		idx += ((start - 0x80000) >> 14);
+		return mtrr_state.fixed_ranges[idx];
+	}
+
+	/* 0xC0000 - 0xFFFFF */
+	idx = 3 * 8;
+	idx += ((start - 0xC0000) >> 12);
+	return mtrr_state.fixed_ranges[idx];
+}
+
+/**
+ * mtrr_type_lookup_variable - look up memory type in MTRR variable entries
+ *
+ * Return Value:
+ * MTRR_TYPE_(type) - Matched memory type or default memory type (unmatched)
+ *
+ * Output Argument:
+ * repeat - Set to 1 when [start:end] spanned across MTRR range and type
+ *	    returned corresponds only to [start:*partial_end].  Caller has
+ *	    to lookup again for [*partial_end:end].
  */
-static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
+static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
+				    int *repeat)
 {
 	int i;
 	u64 base, mask;
 	u8 prev_match, curr_match;
 
 	*repeat = 0;
-	if (!mtrr_state_set)
-		return MTRR_TYPE_INVALID;
-
-	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
-		return MTRR_TYPE_INVALID;
 
-	/* Make end inclusive end, instead of exclusive */
+	/* Make end inclusive instead of exclusive */
 	end--;
 
-	/* Look in fixed ranges. Just return the type as per start */
-	if ((start < 0x100000) &&
-	    (mtrr_state.have_fixed) &&
-	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
-		int idx;
-
-		if (start < 0x80000) {
-			idx = 0;
-			idx += (start >> 16);
-			return mtrr_state.fixed_ranges[idx];
-		} else if (start < 0xC0000) {
-			idx = 1 * 8;
-			idx += ((start - 0x80000) >> 14);
-			return mtrr_state.fixed_ranges[idx];
-		} else {
-			idx = 3 * 8;
-			idx += ((start - 0xC0000) >> 12);
-			return mtrr_state.fixed_ranges[idx];
-		}
-	}
-
-	/*
-	 * Look in variable ranges
-	 * Look of multiple ranges matching this address and pick type
-	 * as per MTRR precedence
-	 */
 	prev_match = MTRR_TYPE_INVALID;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
@@ -186,7 +199,8 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			 * advised to lookup again after having adjusted start
 			 * and end.
 			 *
-			 * Note: This way we handle multiple overlaps as well.
+			 * Note: This way we handle overlaps with multiple
+			 * entries and the default type properly.
 			 */
 			if (start_state)
 				*partial_end = base + get_mtrr_size(mask);
@@ -215,21 +229,18 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			return curr_match;
 	}
 
-	if (mtrr_tom2) {
-		if (start >= (1ULL<<32) && (end < mtrr_tom2))
-			return MTRR_TYPE_WRBACK;
-	}
-
 	if (prev_match != MTRR_TYPE_INVALID)
 		return prev_match;
 
 	return mtrr_state.def_type;
 }
 
-/*
- * Returns the effective MTRR type for the region
- * Error return:
- * MTRR_TYPE_INVALID - when MTRR is not enabled
+/**
+ * mtrr_type_lookup - look up memory type in MTRR
+ *
+ * Return Values:
+ * MTRR_TYPE_(type)  - The effective MTRR type for the region
+ * MTRR_TYPE_INVALID - MTRR is disabled
  */
 u8 mtrr_type_lookup(u64 start, u64 end)
 {
@@ -237,22 +248,45 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 	int repeat;
 	u64 partial_end;
 
-	type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+	if (!mtrr_state_set)
+		return MTRR_TYPE_INVALID;
+
+	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
+		return MTRR_TYPE_INVALID;
+
+	/*
+	 * Look up the fixed ranges first, which take priority over
+	 * the variable ranges.
+	 */
+	if ((start < 0x100000) &&
+	    (mtrr_state.have_fixed) &&
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED))
+		return mtrr_type_lookup_fixed(start, end);
+
+	/*
+	 * Look up the variable ranges.  Look of multiple ranges matching
+	 * this address and pick type as per MTRR precedence.
+	 */
+	type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
 
 	/*
 	 * Common path is with repeat = 0.
 	 * However, we can have cases where [start:end] spans across some
-	 * MTRR range. Do repeated lookups for that case here.
+	 * MTRR ranges and/or the default type.  Do repeated lookups for
+	 * that case here.
 	 */
 	while (repeat) {
 		prev_type = type;
 		start = partial_end;
-		type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+		type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
 
 		if (check_type_overlap(&prev_type, &type))
 			return type;
 	}
 
+	if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
+		return MTRR_TYPE_WRBACK;
+
 	return type;
 }
 
Signature · 1 line
1.9.0.258.g00eda23
#441 lore raw

[tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

x86/mm/mtrr: Clean up mtrr_type_lookup()
Commit-ID:  0cc705f56e400764a171055f727d28a48260bb4b
Gitweb:     http://git.kernel.org/tip/0cc705f56e400764a171055f727d28a48260bb4b
Author:     Toshi Kani <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:08 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:57 +0200

x86/mm/mtrr: Clean up mtrr_type_lookup()

MTRRs contain fixed and variable entries. mtrr_type_lookup() may repeatedly call __mtrr_type_lookup() to handle a request that overlaps with variable entries.

However, __mtrr_type_lookup() also handles the fixed entries, which do not have to be repeated. Therefore, this patch creates separate functions, mtrr_type_lookup_fixed() and mtrr_type_lookup_variable(), to handle the fixed and variable ranges respectively.

The patch also updates the function headers to clarify the return values and output argument. It updates comments to clarify that the repeating is necessary to handle overlaps with the default type, since overlaps with multiple entries alone can be handled without such repeating.

There is no functional change in this patch.

---
 arch/x86/kernel/cpu/mtrr/generic.c | 138 +++++++++++++++++++++++--------------
 1 file changed, 86 insertions(+), 52 deletions(-)
arch/x86/kernel/cpu/mtrr/generic.c +86 -52
index 7b1491c..e51100c 100644
@@ -102,55 +102,68 @@ static int check_type_overlap(u8 *prev, u8 *curr)
 	return 0;
 }
 
-/*
- * Error/Semi-error returns:
- * MTRR_TYPE_INVALID - when MTRR is not enabled
- * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
- *		corresponds only to [start:*partial_end].
- *		Caller has to lookup again for [*partial_end:end].
+/**
+ * mtrr_type_lookup_fixed - look up memory type in MTRR fixed entries
+ *
+ * Return the MTRR fixed memory type of 'start'.
+ *
+ * MTRR fixed entries are divided into the following ways:
+ *  0x00000 - 0x7FFFF : This range is divided into eight 64KB sub-ranges
+ *  0x80000 - 0xBFFFF : This range is divided into sixteen 16KB sub-ranges
+ *  0xC0000 - 0xFFFFF : This range is divided into sixty-four 4KB sub-ranges
+ *
+ * Return Values:
+ * MTRR_TYPE_(type)  - Matched memory type
+ * MTRR_TYPE_INVALID - Unmatched
+ */
+static u8 mtrr_type_lookup_fixed(u64 start, u64 end)
+{
+	int idx;
+
+	if (start >= 0x100000)
+		return MTRR_TYPE_INVALID;
+
+	/* 0x0 - 0x7FFFF */
+	if (start < 0x80000) {
+		idx = 0;
+		idx += (start >> 16);
+		return mtrr_state.fixed_ranges[idx];
+	/* 0x80000 - 0xBFFFF */
+	} else if (start < 0xC0000) {
+		idx = 1 * 8;
+		idx += ((start - 0x80000) >> 14);
+		return mtrr_state.fixed_ranges[idx];
+	}
+
+	/* 0xC0000 - 0xFFFFF */
+	idx = 3 * 8;
+	idx += ((start - 0xC0000) >> 12);
+	return mtrr_state.fixed_ranges[idx];
+}
+
+/**
+ * mtrr_type_lookup_variable - look up memory type in MTRR variable entries
+ *
+ * Return Value:
+ * MTRR_TYPE_(type) - Matched memory type or default memory type (unmatched)
+ *
+ * Output Argument:
+ * repeat - Set to 1 when [start:end] spanned across MTRR range and type
+ *	    returned corresponds only to [start:*partial_end].  Caller has
+ *	    to lookup again for [*partial_end:end].
  */
-static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
+static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
+				    int *repeat)
 {
 	int i;
 	u64 base, mask;
 	u8 prev_match, curr_match;
 
 	*repeat = 0;
-	if (!mtrr_state_set)
-		return MTRR_TYPE_INVALID;
-
-	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
-		return MTRR_TYPE_INVALID;
 
-	/* Make end inclusive end, instead of exclusive */
+	/* Make end inclusive instead of exclusive */
 	end--;
 
-	/* Look in fixed ranges. Just return the type as per start */
-	if ((start < 0x100000) &&
-	    (mtrr_state.have_fixed) &&
-	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
-		int idx;
-
-		if (start < 0x80000) {
-			idx = 0;
-			idx += (start >> 16);
-			return mtrr_state.fixed_ranges[idx];
-		} else if (start < 0xC0000) {
-			idx = 1 * 8;
-			idx += ((start - 0x80000) >> 14);
-			return mtrr_state.fixed_ranges[idx];
-		} else {
-			idx = 3 * 8;
-			idx += ((start - 0xC0000) >> 12);
-			return mtrr_state.fixed_ranges[idx];
-		}
-	}
-
-	/*
-	 * Look in variable ranges
-	 * Look of multiple ranges matching this address and pick type
-	 * as per MTRR precedence
-	 */
 	prev_match = MTRR_TYPE_INVALID;
 	for (i = 0; i < num_var_ranges; ++i) {
 		unsigned short start_state, end_state, inclusive;
@@ -186,7 +199,8 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			 * advised to lookup again after having adjusted start
 			 * and end.
 			 *
-			 * Note: This way we handle multiple overlaps as well.
+			 * Note: This way we handle overlaps with multiple
+			 * entries and the default type properly.
 			 */
 			if (start_state)
 				*partial_end = base + get_mtrr_size(mask);
@@ -215,21 +229,18 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 			return curr_match;
 	}
 
-	if (mtrr_tom2) {
-		if (start >= (1ULL<<32) && (end < mtrr_tom2))
-			return MTRR_TYPE_WRBACK;
-	}
-
 	if (prev_match != MTRR_TYPE_INVALID)
 		return prev_match;
 
 	return mtrr_state.def_type;
 }
 
-/*
- * Returns the effective MTRR type for the region
- * Error return:
- * MTRR_TYPE_INVALID - when MTRR is not enabled
+/**
+ * mtrr_type_lookup - look up memory type in MTRR
+ *
+ * Return Values:
+ * MTRR_TYPE_(type)  - The effective MTRR type for the region
+ * MTRR_TYPE_INVALID - MTRR is disabled
  */
 u8 mtrr_type_lookup(u64 start, u64 end)
 {
@@ -237,22 +248,45 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 	int repeat;
 	u64 partial_end;
 
-	type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+	if (!mtrr_state_set)
+		return MTRR_TYPE_INVALID;
+
+	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
+		return MTRR_TYPE_INVALID;
+
+	/*
+	 * Look up the fixed ranges first, which take priority over
+	 * the variable ranges.
+	 */
+	if ((start < 0x100000) &&
+	    (mtrr_state.have_fixed) &&
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED))
+		return mtrr_type_lookup_fixed(start, end);
+
+	/*
+	 * Look up the variable ranges.  Look of multiple ranges matching
+	 * this address and pick type as per MTRR precedence.
+	 */
+	type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
 
 	/*
 	 * Common path is with repeat = 0.
 	 * However, we can have cases where [start:end] spans across some
-	 * MTRR range. Do repeated lookups for that case here.
+	 * MTRR ranges and/or the default type.  Do repeated lookups for
+	 * that case here.
 	 */
 	while (repeat) {
 		prev_type = type;
 		start = partial_end;
-		type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+		type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
 
 		if (check_type_overlap(&prev_type, &type))
 			return type;
 	}
 
+	if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
+		return MTRR_TYPE_WRBACK;
+
 	return type;
 }
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#442 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 44 lines · tip-bot for Toshi Kani
(quoted diff) +29 -0
+/**
+ * mtrr_type_lookup - look up memory type in MTRR
+ *
+ * Return Values:
+ * MTRR_TYPE_(type)  - The effective MTRR type for the region
+ * MTRR_TYPE_INVALID - MTRR is disabled
  */
 u8 mtrr_type_lookup(u64 start, u64 end)
 {
 
 	int repeat;
 	u64 partial_end;
 
+	if (!mtrr_state_set)
+		return MTRR_TYPE_INVALID;
+
+	if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
+		return MTRR_TYPE_INVALID;
+
+	/*
+	 * Look up the fixed ranges first, which take priority over
+	 * the variable ranges.
+	 */
+	if ((start < 0x100000) &&
+	    (mtrr_state.have_fixed) &&
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED))
+		return mtrr_type_lookup_fixed(start, end);
+
+	/*
+	 * Look up the variable ranges.  Look of multiple ranges matching
+	 * this address and pick type as per MTRR precedence.
+	 */
+	type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
 
 	/*
 	 * Common path is with repeat = 0.
 	 * However, we can have cases where [start:end] spans across some
+	 * MTRR ranges and/or the default type.  Do repeated lookups for
+	 * that case here.
 	 */
 	while (repeat) {
 		prev_type = type;
 		start = partial_end;
+		type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);

Review

Quoted 10 lines
(quoted diff) +3 -0
 
 		if (check_type_overlap(&prev_type, &type))
 			return type;
 	}
 
+	if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
+		return MTRR_TYPE_WRBACK;
+
 	return type;
 }

So I got staring at this MTRR horror show because I _really_ _Really_ want to kill stop_machine_from_inactive_cpu().

But I wondered about these lookup functions, should they not have an assertion that preemption is disabled?

Using these functions with preemption enabled is racy against MTRR updates. And if that race is ok, at the very least explain that it is indeed racy and why this is not a problem.

maintainer
#443 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 3 lines · Peter Zijlstra

Using these functions with preemption enabled is racy against MTRR updates. And if that race is ok, at the very least explain that it is indeed racy and why this is not a problem.

Right, so Luis has been working on burying direct MTRR access so after that work is done, we'll be using only PAT for changing memory attributes. Look at arch_phys_wc_add() and all those fbdev users of mtrr_add() which get converted to that thing...

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
maintainer
#444 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 9 lines · Borislav Petkov
Quoted 3 lines · Peter Zijlstra

Using these functions with preemption enabled is racy against MTRR updates. And if that race is ok, at the very least explain that it is indeed racy and why this is not a problem.

Right, so Luis has been working on burying direct MTRR access so after that work is done, we'll be using only PAT for changing memory attributes. Look at arch_phys_wc_add() and all those fbdev users of mtrr_add() which get converted to that thing...

Drivers don't do those lookups afaict.

But its things like set_memory_XX(), and afaict that's all buggy against MTRR modifications.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#445 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 2 lines · Peter Zijlstra

But its things like set_memory_XX(), and afaict that's all buggy against MTRR modifications.

I think the idea is to not do any MTRR modifications at some point:

Quoted 1 line

From Documentation/x86/pat.txt:

"... Ideally mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add() is made, should already have been ioremapped with WC attributes or PAT entries, this can be done by using ioremap_wc() / set_memory_wc()."

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#446 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Peter Zijlstra

But its things like set_memory_XX(), and afaict that's all buggy against MTRR modifications.

I think the idea is to not do any MTRR modifications at some point:

Quoted 7 lines

From Documentation/x86/pat.txt:

"... Ideally mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add() is made, should already have been ioremapped with WC attributes or PAT entries, this can be done by using ioremap_wc() / set_memory_wc()."

I need to update this documentation to remove set_memory_wc() there as we've learned with the MTRR --> PAT conversion that set_memory_wc() cannot be used on IO memory, it can only be used for RAM. I am not sure if I would call it being broken that you cannot use set_memory_*() for IO memory that may have been by design.

Luis

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#447 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 5 lines · Luis R. Rodriguez

I need to update this documentation to remove set_memory_wc() there as we've learned with the MTRR --> PAT conversion that set_memory_wc() cannot be used on IO memory, it can only be used for RAM. I am not sure if I would call it being broken that you cannot use set_memory_*() for IO memory that may have been by design.

Well, it doesn't really make sense to write-combine IO memory, does it? My simplistic impression is that an IO range behind which there's a device, cannot stomach any caching of IO as all commands/data accesses need to happen as they get issued...

Signature · 11 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#448 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 2 lines · Borislav Petkov

Well, it doesn't really make sense to write-combine IO memory, does it?

Quite the reverse.

It makes no sense to write-combine normal memory (RAM), because caches work and sane memory is always cache-coherent. So marking regular memory write-combining is a sign of crap hardware (which admittedly exists all too much, but hopefully goes away).

In contrast, marking MMIO memory write-combining is not a sign of crap hardware - it's just a sign of things like frame buffers on the card etc. Which very much wants write combining. So WC for MMIO at least makes sense.

Yes, yes, I realize that "crap hardware" may actually be the more common case, but still..

Linus

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#449 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 7 lines · Linus Torvalds

Quite the reverse.

It makes no sense to write-combine normal memory (RAM), because caches work and sane memory is always cache-coherent. So marking regular memory write-combining is a sign of crap hardware (which admittedly exists all too much, but hopefully goes away).

Quoted 7 lines

In contrast, marking MMIO memory write-combining is not a sign of crap hardware - it's just a sign of things like frame buffers on the card etc. Which very much wants write combining. So WC for MMIO at least makes sense.

Yes, yes, I realize that "crap hardware" may actually be the more common case, but still..

Hmm, ok.

My simplistic mental picture while thinking of this is the IO range where you send the commands to the device and you don't really want to delay those but they should reach the device as they get issued.

OTOH, your example with frame buffers really wants to WC because sending down each write separately is plain dumb.

Ok, I see, so it can make sense to have WC IO memory, depending on the range and what you're going to use it for, I guess...

Thanks.

Signature · 11 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#450 lore raw

Re: [tip:x86/mm] x86/mm/mtrr: Clean up mtrr_type_lookup()

Quoted 4 lines · Borislav Petkov

My simplistic mental picture while thinking of this is the IO range where you send the commands to the device and you don't really want to delay those but they should reach the device as they get issued.

Well, even for command streams, people often do go for a write-combining approach, simply because it is *so* much more efficient on the bus to buffer and burst things. The interface is set up to not really "combine" things in the over-writing sense, but just in the "combine continuous writes into bigger buffers on the CPU, and then write it out as efficiently as possible" sense.

Of course, the device (and the driver) has to be designed properly for that, and it makes sense only with certain kinds of models, but it can actually be much more efficient to make the device interface be something like "write 32-byte command packets to a circular write-combining buffer" than it is to do things other ways. Back in the days, that was one of the most efficient ways to try to fill up the PCI bandwidth.

There are other approaches too, of course, with the modern variation tending to be "the device does all real accesses by reading over DMA, and the only time you use IO accesses is for setup and as a 'start your DMA transfers now' kind of interface". But write-combining MMIO used to be a very common model for high-performace IO not that long ago, because DMA didn't actually use to be all that efficient at all (nasty behavior with caches and snooping etc back before the memory controller was on-die and DMA accesses snooped caches directly). So the "DMA is efficient even for smaller things" thing is relatively recent.

Linus

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#451 lore raw

PATCH 6/18 x86/process: Drop repeated word from comment

In reply to Borislav Petkov

From: Huang Rui <[email protected]>

A single "default" is fine.

---
 arch/x86/kernel/process.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
arch/x86/kernel/process.c +3 -4
index 6e338e3b1dc0..c648139d68d7 100644
@@ -445,11 +445,10 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 }
 
 /*
- * MONITOR/MWAIT with no hints, used for default default C1 state.
- * This invokes MWAIT with interrutps enabled and no flags,
- * which is backwards compatible with the original MWAIT implementation.
+ * MONITOR/MWAIT with no hints, used for default C1 state. This invokes MWAIT
+ * with interrupts enabled and no flags, which is backwards compatible with the
+ * original MWAIT implementation.
  */
-
 static void mwait_idle(void)
 {
 	if (!current_set_polling_and_test()) {
Signature · 1 line
1.9.0.258.g00eda23
#452 lore raw

[tip:sched/core] sched/x86: Drop repeated word from mwait_idle() comment

sched/x86: Drop repeated word from mwait_idle() comment
Commit-ID:  0fb0328d3458ff2d6ffbb280b75053c99a8a4b1f
Gitweb:     http://git.kernel.org/tip/0fb0328d3458ff2d6ffbb280b75053c99a8a4b1f
Author:     Huang Rui <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:09 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:38:04 +0200

sched/x86: Drop repeated word from mwait_idle() comment

A single "default" is fine.

[ Fix another typo and reflow comment. ]
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/kernel/process.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
arch/x86/kernel/process.c +3 -4
index 6e338e3..c648139 100644
@@ -445,11 +445,10 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 }
 
 /*
- * MONITOR/MWAIT with no hints, used for default default C1 state.
- * This invokes MWAIT with interrutps enabled and no flags,
- * which is backwards compatible with the original MWAIT implementation.
+ * MONITOR/MWAIT with no hints, used for default C1 state. This invokes MWAIT
+ * with interrupts enabled and no flags, which is backwards compatible with the
+ * original MWAIT implementation.
  */
-
 static void mwait_idle(void)
 {
 	if (!current_set_polling_and_test()) {
maintainer
#453 lore raw

PATCH 7/18 x86/mm: Enhance MTRR checks in kernel mapping helpers

In reply to Borislav Petkov

From: Toshi Kani <[email protected]>

This patch adds the argument 'uniform' to mtrr_type_lookup(), which gets set to 1 when a given range is covered uniformly by MTRRs, i.e. the range is fully covered by a single MTRR entry or the default type.

Change pud_set_huge() and pmd_set_huge() to honor the 'uniform' flag to see if it is safe to create a huge page mapping in the range.

This allows them to create a huge page mapping in a range covered by a single MTRR entry of any memory type. It also detects a non-optimal request properly. They continue to check with the WB type since it does not effectively change the uniform mapping even if a request spans multiple MTRR entries.

pmd_set_huge() logs a warning message to a non-optimal request so that driver writers will be aware of such a case. Drivers should make a mapping request aligned to a single MTRR entry when the range is covered by MTRRs.

Cc Luis R. Rodriguez <[email protected]>
Cc Andrew Morton <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc linux-mm <[email protected]>
Cc x86-ml <[email protected]>
[ Realign, flesh out comments, improve warning message. ]
---
 arch/x86/include/asm/mtrr.h        |  4 ++--
 arch/x86/kernel/cpu/mtrr/generic.c | 40 ++++++++++++++++++++++++++++----------
 arch/x86/mm/pat.c                  |  4 ++--
 arch/x86/mm/pgtable.c              | 38 +++++++++++++++++++++++-------------
 4 files changed, 58 insertions(+), 28 deletions(-)
arch/x86/include/asm/mtrr.h +2 -2
index bb03a547c1ab..a31759e1edd9 100644
@@ -31,7 +31,7 @@
  * arch_phys_wc_add and arch_phys_wc_del.
  */
 # ifdef CONFIG_MTRR
-extern u8 mtrr_type_lookup(u64 addr, u64 end);
+extern u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform);
 extern void mtrr_save_fixed_ranges(void *);
 extern void mtrr_save_state(void);
 extern int mtrr_add(unsigned long base, unsigned long size,
@@ -50,7 +50,7 @@ extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
 extern int amd_special_default_mtrr(void);
 extern int phys_wc_to_mtrr_index(int handle);
 #  else
-static inline u8 mtrr_type_lookup(u64 addr, u64 end)
+static inline u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform)
 {
 	/*
 	 * Return no-MTRRs:
arch/x86/kernel/cpu/mtrr/generic.c +30 -10
index e51100c49eea..f782d9b62cb3 100644
@@ -147,19 +147,24 @@ static u8 mtrr_type_lookup_fixed(u64 start, u64 end)
  * Return Value:
  * MTRR_TYPE_(type) - Matched memory type or default memory type (unmatched)
  *
- * Output Argument:
+ * Output Arguments:
  * repeat - Set to 1 when [start:end] spanned across MTRR range and type
  *	    returned corresponds only to [start:*partial_end].  Caller has
  *	    to lookup again for [*partial_end:end].
+ *
+ * uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
+ *	     region is fully covered by a single MTRR entry or the default
+ *	     type.
  */
 static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
-				    int *repeat)
+				    int *repeat, u8 *uniform)
 {
 	int i;
 	u64 base, mask;
 	u8 prev_match, curr_match;
 
 	*repeat = 0;
+	*uniform = 1;
 
 	/* Make end inclusive instead of exclusive */
 	end--;
@@ -214,6 +219,7 @@ static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
 
 			end = *partial_end - 1; /* end is inclusive */
 			*repeat = 1;
+			*uniform = 0;
 		}
 
 		if ((start & mask) != (base & mask))
@@ -225,6 +231,7 @@ static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
 			continue;
 		}
 
+		*uniform = 0;
 		if (check_type_overlap(&prev_match, &curr_match))
 			return curr_match;
 	}
@@ -241,10 +248,15 @@ static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
  * Return Values:
  * MTRR_TYPE_(type)  - The effective MTRR type for the region
  * MTRR_TYPE_INVALID - MTRR is disabled
+ *
+ * Output Argument:
+ * uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
+ *	     region is fully covered by a single MTRR entry or the default
+ *	     type.
  */
-u8 mtrr_type_lookup(u64 start, u64 end)
+u8 mtrr_type_lookup(u64 start, u64 end, u8 *uniform)
 {
-	u8 type, prev_type;
+	u8 type, prev_type, is_uniform = 1, dummy;
 	int repeat;
 	u64 partial_end;
 
@@ -260,14 +272,18 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 	 */
 	if ((start < 0x100000) &&
 	    (mtrr_state.have_fixed) &&
-	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED))
-		return mtrr_type_lookup_fixed(start, end);
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
+		is_uniform = 0;
+		type = mtrr_type_lookup_fixed(start, end);
+		goto out;
+	}
 
 	/*
 	 * Look up the variable ranges.  Look of multiple ranges matching
 	 * this address and pick type as per MTRR precedence.
 	 */
-	type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
+	type = mtrr_type_lookup_variable(start, end, &partial_end,
+					 &repeat, &is_uniform);
 
 	/*
 	 * Common path is with repeat = 0.
@@ -278,15 +294,19 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 	while (repeat) {
 		prev_type = type;
 		start = partial_end;
-		type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
+		is_uniform = 0;
+		type = mtrr_type_lookup_variable(start, end, &partial_end,
+						 &repeat, &dummy);
 
 		if (check_type_overlap(&prev_type, &type))
-			return type;
+			goto out;
 	}
 
 	if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
-		return MTRR_TYPE_WRBACK;
+		type = MTRR_TYPE_WRBACK;
 
+out:
+	*uniform = is_uniform;
 	return type;
 }
 
arch/x86/mm/pat.c +2 -2
index 35af6771a95a..372ad422c2c3 100644
@@ -267,9 +267,9 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end,
 	 * request is for WB.
 	 */
 	if (req_type == _PAGE_CACHE_MODE_WB) {
-		u8 mtrr_type;
+		u8 mtrr_type, uniform;
 
-		mtrr_type = mtrr_type_lookup(start, end);
+		mtrr_type = mtrr_type_lookup(start, end, &uniform);
 		if (mtrr_type != MTRR_TYPE_WRBACK)
 			return _PAGE_CACHE_MODE_UC_MINUS;
 
arch/x86/mm/pgtable.c +24 -14
index c30f9819786b..fb0a9dd1d6e4 100644
@@ -566,19 +566,28 @@ void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys,
 /**
  * pud_set_huge - setup kernel PUD mapping
  *
- * MTRR can override PAT memory types with 4KiB granularity.  Therefore,
- * this function does not set up a huge page when the range is covered
- * by a non-WB type of MTRR.  MTRR_TYPE_INVALID indicates that MTRR are
- * disabled.
+ * MTRRs can override PAT memory types with 4KiB granularity. Therefore, this
+ * function sets up a huge page only if any of the following conditions are met:
+ *
+ * - MTRRs are disabled, or
+ *
+ * - MTRRs are enabled and the range is completely covered by a single MTRR, or
+ *
+ * - MTRRs are enabled and the corresponding MTRR memory type is WB, which
+ *   has no effect on the requested PAT memory type.
+ *
+ * Callers should try to decrease page size (1GB -> 2MB -> 4K) if the bigger
+ * page mapping attempt fails.
  *
  * Returns 1 on success and 0 on failure.
  */
 int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 {
-	u8 mtrr;
+	u8 mtrr, uniform;
 
-	mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE);
-	if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != MTRR_TYPE_INVALID))
+	mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE, &uniform);
+	if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+	    (mtrr != MTRR_TYPE_WRBACK))
 		return 0;
 
 	prot = pgprot_4k_2_large(prot);
@@ -593,20 +602,21 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 /**
  * pmd_set_huge - setup kernel PMD mapping
  *
- * MTRR can override PAT memory types with 4KiB granularity.  Therefore,
- * this function does not set up a huge page when the range is covered
- * by a non-WB type of MTRR.  MTRR_TYPE_INVALID indicates that MTRR are
- * disabled.
+ * See text over pud_set_huge() above.
  *
  * Returns 1 on success and 0 on failure.
  */
 int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
 {
-	u8 mtrr;
+	u8 mtrr, uniform;
 
-	mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE);
-	if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != MTRR_TYPE_INVALID))
+	mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE, &uniform);
+	if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+	    (mtrr != MTRR_TYPE_WRBACK)) {
+		pr_warn_once("%s: Cannot satisfy [mem %#010llx-%#010llx] with a huge-page mapping due to MTRR override.\n",
+			     __func__, addr, addr + PMD_SIZE);
 		return 0;
+	}
 
 	prot = pgprot_4k_2_large(prot);
 
Signature · 1 line
1.9.0.258.g00eda23
#454 lore raw

[tip:x86/mm] x86/mm/mtrr: Enhance MTRR checks in kernel mapping helpers

x86/mm/mtrr: Enhance MTRR checks in kernel mapping helpers
Commit-ID:  b73522e0c1be58d3c69b124985b8ccf94e3677f7
Gitweb:     http://git.kernel.org/tip/b73522e0c1be58d3c69b124985b8ccf94e3677f7
Author:     Toshi Kani <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:10 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:58 +0200

x86/mm/mtrr: Enhance MTRR checks in kernel mapping helpers

This patch adds the argument 'uniform' to mtrr_type_lookup(), which gets set to 1 when a given range is covered uniformly by MTRRs, i.e. the range is fully covered by a single MTRR entry or the default type.

Change pud_set_huge() and pmd_set_huge() to honor the 'uniform' flag to see if it is safe to create a huge page mapping in the range.

This allows them to create a huge page mapping in a range covered by a single MTRR entry of any memory type. It also detects a non-optimal request properly. They continue to check with the WB type since it does not effectively change the uniform mapping even if a request spans multiple MTRR entries.

pmd_set_huge() logs a warning message to a non-optimal request so that driver writers will be aware of such a case. Drivers should make a mapping request aligned to a single MTRR entry when the range is covered by MTRRs.

[ Realign, flesh out comments, improve warning message. ]
Cc Andrew Morton <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Luis R. Rodriguez <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc linux-mm <[email protected]>
---
 arch/x86/include/asm/mtrr.h        |  4 ++--
 arch/x86/kernel/cpu/mtrr/generic.c | 40 ++++++++++++++++++++++++++++----------
 arch/x86/mm/pat.c                  |  4 ++--
 arch/x86/mm/pgtable.c              | 38 +++++++++++++++++++++++-------------
 4 files changed, 58 insertions(+), 28 deletions(-)
arch/x86/include/asm/mtrr.h +2 -2
index bb03a54..a31759e 100644
@@ -31,7 +31,7 @@
  * arch_phys_wc_add and arch_phys_wc_del.
  */
 # ifdef CONFIG_MTRR
-extern u8 mtrr_type_lookup(u64 addr, u64 end);
+extern u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform);
 extern void mtrr_save_fixed_ranges(void *);
 extern void mtrr_save_state(void);
 extern int mtrr_add(unsigned long base, unsigned long size,
@@ -50,7 +50,7 @@ extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
 extern int amd_special_default_mtrr(void);
 extern int phys_wc_to_mtrr_index(int handle);
 #  else
-static inline u8 mtrr_type_lookup(u64 addr, u64 end)
+static inline u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform)
 {
 	/*
 	 * Return no-MTRRs:
arch/x86/kernel/cpu/mtrr/generic.c +30 -10
index e51100c..f782d9b 100644
@@ -147,19 +147,24 @@ static u8 mtrr_type_lookup_fixed(u64 start, u64 end)
  * Return Value:
  * MTRR_TYPE_(type) - Matched memory type or default memory type (unmatched)
  *
- * Output Argument:
+ * Output Arguments:
  * repeat - Set to 1 when [start:end] spanned across MTRR range and type
  *	    returned corresponds only to [start:*partial_end].  Caller has
  *	    to lookup again for [*partial_end:end].
+ *
+ * uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
+ *	     region is fully covered by a single MTRR entry or the default
+ *	     type.
  */
 static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
-				    int *repeat)
+				    int *repeat, u8 *uniform)
 {
 	int i;
 	u64 base, mask;
 	u8 prev_match, curr_match;
 
 	*repeat = 0;
+	*uniform = 1;
 
 	/* Make end inclusive instead of exclusive */
 	end--;
@@ -214,6 +219,7 @@ static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
 
 			end = *partial_end - 1; /* end is inclusive */
 			*repeat = 1;
+			*uniform = 0;
 		}
 
 		if ((start & mask) != (base & mask))
@@ -225,6 +231,7 @@ static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
 			continue;
 		}
 
+		*uniform = 0;
 		if (check_type_overlap(&prev_match, &curr_match))
 			return curr_match;
 	}
@@ -241,10 +248,15 @@ static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
  * Return Values:
  * MTRR_TYPE_(type)  - The effective MTRR type for the region
  * MTRR_TYPE_INVALID - MTRR is disabled
+ *
+ * Output Argument:
+ * uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
+ *	     region is fully covered by a single MTRR entry or the default
+ *	     type.
  */
-u8 mtrr_type_lookup(u64 start, u64 end)
+u8 mtrr_type_lookup(u64 start, u64 end, u8 *uniform)
 {
-	u8 type, prev_type;
+	u8 type, prev_type, is_uniform = 1, dummy;
 	int repeat;
 	u64 partial_end;
 
@@ -260,14 +272,18 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 	 */
 	if ((start < 0x100000) &&
 	    (mtrr_state.have_fixed) &&
-	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED))
-		return mtrr_type_lookup_fixed(start, end);
+	    (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
+		is_uniform = 0;
+		type = mtrr_type_lookup_fixed(start, end);
+		goto out;
+	}
 
 	/*
 	 * Look up the variable ranges.  Look of multiple ranges matching
 	 * this address and pick type as per MTRR precedence.
 	 */
-	type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
+	type = mtrr_type_lookup_variable(start, end, &partial_end,
+					 &repeat, &is_uniform);
 
 	/*
 	 * Common path is with repeat = 0.
@@ -278,15 +294,19 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 	while (repeat) {
 		prev_type = type;
 		start = partial_end;
-		type = mtrr_type_lookup_variable(start, end, &partial_end, &repeat);
+		is_uniform = 0;
+		type = mtrr_type_lookup_variable(start, end, &partial_end,
+						 &repeat, &dummy);
 
 		if (check_type_overlap(&prev_type, &type))
-			return type;
+			goto out;
 	}
 
 	if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
-		return MTRR_TYPE_WRBACK;
+		type = MTRR_TYPE_WRBACK;
 
+out:
+	*uniform = is_uniform;
 	return type;
 }
 
arch/x86/mm/pat.c +2 -2
index 35af677..372ad42 100644
@@ -267,9 +267,9 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end,
 	 * request is for WB.
 	 */
 	if (req_type == _PAGE_CACHE_MODE_WB) {
-		u8 mtrr_type;
+		u8 mtrr_type, uniform;
 
-		mtrr_type = mtrr_type_lookup(start, end);
+		mtrr_type = mtrr_type_lookup(start, end, &uniform);
 		if (mtrr_type != MTRR_TYPE_WRBACK)
 			return _PAGE_CACHE_MODE_UC_MINUS;
 
arch/x86/mm/pgtable.c +24 -14
index c30f981..fb0a9dd 100644
@@ -566,19 +566,28 @@ void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys,
 /**
  * pud_set_huge - setup kernel PUD mapping
  *
- * MTRR can override PAT memory types with 4KiB granularity.  Therefore,
- * this function does not set up a huge page when the range is covered
- * by a non-WB type of MTRR.  MTRR_TYPE_INVALID indicates that MTRR are
- * disabled.
+ * MTRRs can override PAT memory types with 4KiB granularity. Therefore, this
+ * function sets up a huge page only if any of the following conditions are met:
+ *
+ * - MTRRs are disabled, or
+ *
+ * - MTRRs are enabled and the range is completely covered by a single MTRR, or
+ *
+ * - MTRRs are enabled and the corresponding MTRR memory type is WB, which
+ *   has no effect on the requested PAT memory type.
+ *
+ * Callers should try to decrease page size (1GB -> 2MB -> 4K) if the bigger
+ * page mapping attempt fails.
  *
  * Returns 1 on success and 0 on failure.
  */
 int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 {
-	u8 mtrr;
+	u8 mtrr, uniform;
 
-	mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE);
-	if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != MTRR_TYPE_INVALID))
+	mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE, &uniform);
+	if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+	    (mtrr != MTRR_TYPE_WRBACK))
 		return 0;
 
 	prot = pgprot_4k_2_large(prot);
@@ -593,20 +602,21 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 /**
  * pmd_set_huge - setup kernel PMD mapping
  *
- * MTRR can override PAT memory types with 4KiB granularity.  Therefore,
- * this function does not set up a huge page when the range is covered
- * by a non-WB type of MTRR.  MTRR_TYPE_INVALID indicates that MTRR are
- * disabled.
+ * See text over pud_set_huge() above.
  *
  * Returns 1 on success and 0 on failure.
  */
 int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
 {
-	u8 mtrr;
+	u8 mtrr, uniform;
 
-	mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE);
-	if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != MTRR_TYPE_INVALID))
+	mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE, &uniform);
+	if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+	    (mtrr != MTRR_TYPE_WRBACK)) {
+		pr_warn_once("%s: Cannot satisfy [mem %#010llx-%#010llx] with a huge-page mapping due to MTRR override.\n",
+			     __func__, addr, addr + PMD_SIZE);
 		return 0;
+	}
 
 	prot = pgprot_4k_2_large(prot);
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#455 lore raw

PATCH 8/18 x86/mm/pat: Convert to pr_* usage

In reply to Borislav Petkov

From: "Luis R. Rodriguez" <[email protected]>

Use pr_info() instead of the old printk to prefix the component where things are coming from. With this readers will know exactly where the message is coming from. We use pr_* helpers but define pr_fmt to the empty string for easier grepping for those error messages.

We leave the users of dprintk() in place, this will print only when the debugpat kernel parameter is enabled. We want to leave those enabled as a debug feature, but also make them use the same prefix.

Cc Andy Walls <[email protected]>
Cc Doug Ledford <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Bjorn Helgaas <[email protected]>
Cc Michael S. Tsirkin <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc H. Peter Anvin <[email protected]>
[ Kill pr_fmt. ]
---
 arch/x86/mm/pat.c          | 44 ++++++++++++++++++++++----------------------
 arch/x86/mm/pat_internal.h |  2 +-
 arch/x86/mm/pat_rbtree.c   |  6 +++---
 3 files changed, 26 insertions(+), 26 deletions(-)
arch/x86/mm/pat.c +22 -22
index 372ad422c2c3..8c50b9bfa996 100644
@@ -33,13 +33,16 @@
 #include "pat_internal.h"
 #include "mm_internal.h"
 
+#undef pr_fmt
+#define pr_fmt(fmt) "" fmt
+
 #ifdef CONFIG_X86_PAT
 int __read_mostly pat_enabled = 1;
 
 static inline void pat_disable(const char *reason)
 {
 	pat_enabled = 0;
-	printk(KERN_INFO "%s\n", reason);
+	pr_info("x86/PAT: %s\n", reason);
 }
 
 static int __init nopat(char *str)
@@ -188,7 +191,7 @@ void pat_init_cache_modes(void)
 					   pat_msg + 4 * i);
 		update_cache_mode_entry(i, cache);
 	}
-	pr_info("PAT configuration [0-7]: %s\n", pat_msg);
+	pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg);
 }
 
 #define PAT(x, y)	((u64)PAT_ ## y << ((x)*8))
@@ -211,8 +214,7 @@ void pat_init(void)
 			 * switched to PAT on the boot CPU. We have no way to
 			 * undo PAT.
 			 */
-			printk(KERN_ERR "PAT enabled, "
-			       "but not supported by secondary CPU\n");
+			pr_err("x86/PAT: PAT enabled, but not supported by secondary CPU\n");
 			BUG();
 		}
 	}
@@ -347,7 +349,7 @@ static int reserve_ram_pages_type(u64 start, u64 end,
 		page = pfn_to_page(pfn);
 		type = get_page_memtype(page);
 		if (type != -1) {
-			pr_info("reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
+			pr_info("x86/PAT: reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
 				start, end - 1, type, req_type);
 			if (new_type)
 				*new_type = type;
@@ -451,9 +453,9 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
 
 	err = rbt_memtype_check_insert(new, new_type);
 	if (err) {
-		printk(KERN_INFO "reserve_memtype failed [mem %#010Lx-%#010Lx], track %s, req %s\n",
-		       start, end - 1,
-		       cattr_name(new->type), cattr_name(req_type));
+		pr_info("x86/PAT: reserve_memtype failed [mem %#010Lx-%#010Lx], track %s, req %s\n",
+			start, end - 1,
+			cattr_name(new->type), cattr_name(req_type));
 		kfree(new);
 		spin_unlock(&memtype_lock);
 
@@ -497,8 +499,8 @@ int free_memtype(u64 start, u64 end)
 	spin_unlock(&memtype_lock);
 
 	if (!entry) {
-		printk(KERN_INFO "%s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
-		       current->comm, current->pid, start, end - 1);
+		pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
+			current->comm, current->pid, start, end - 1);
 		return -EINVAL;
 	}
 
@@ -628,8 +630,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 
 	while (cursor < to) {
 		if (!devmem_is_allowed(pfn)) {
-			printk(KERN_INFO "Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
-			       current->comm, from, to - 1);
+			pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
+				current->comm, from, to - 1);
 			return 0;
 		}
 		cursor += PAGE_SIZE;
@@ -698,8 +700,7 @@ int kernel_map_sync_memtype(u64 base, unsigned long size,
 				size;
 
 	if (ioremap_change_attr((unsigned long)__va(base), id_sz, pcm) < 0) {
-		printk(KERN_INFO "%s:%d ioremap_change_attr failed %s "
-			"for [mem %#010Lx-%#010Lx]\n",
+		pr_info("x86/PAT: %s:%d ioremap_change_attr failed %s for [mem %#010Lx-%#010Lx]\n",
 			current->comm, current->pid,
 			cattr_name(pcm),
 			base, (unsigned long long)(base + size-1));
@@ -734,7 +735,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 
 		pcm = lookup_memtype(paddr);
 		if (want_pcm != pcm) {
-			printk(KERN_WARNING "%s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
+			pr_warn("x86/PAT: %s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
 				current->comm, current->pid,
 				cattr_name(want_pcm),
 				(unsigned long long)paddr,
@@ -755,13 +756,12 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 		if (strict_prot ||
 		    !is_new_memtype_allowed(paddr, size, want_pcm, pcm)) {
 			free_memtype(paddr, paddr + size);
-			printk(KERN_ERR "%s:%d map pfn expected mapping type %s"
-				" for [mem %#010Lx-%#010Lx], got %s\n",
-				current->comm, current->pid,
-				cattr_name(want_pcm),
-				(unsigned long long)paddr,
-				(unsigned long long)(paddr + size - 1),
-				cattr_name(pcm));
+			pr_err("x86/PAT: %s:%d map pfn expected mapping type %s for [mem %#010Lx-%#010Lx], got %s\n",
+			       current->comm, current->pid,
+			       cattr_name(want_pcm),
+			       (unsigned long long)paddr,
+			       (unsigned long long)(paddr + size - 1),
+			       cattr_name(pcm));
 			return -EINVAL;
 		}
 		/*
arch/x86/mm/pat_internal.h +1 -1
index f6411620305d..a739bfc40690 100644
@@ -4,7 +4,7 @@
 extern int pat_debug_enable;
 
 #define dprintk(fmt, arg...) \
-	do { if (pat_debug_enable) printk(KERN_INFO fmt, ##arg); } while (0)
+	do { if (pat_debug_enable) pr_info("x86/PAT: " fmt, ##arg); } while (0)
 
 struct memtype {
 	u64			start;
arch/x86/mm/pat_rbtree.c +3 -3
index 6582adcc8bd9..63931080366a 100644
@@ -160,9 +160,9 @@ success:
 	return 0;
 
 failure:
-	printk(KERN_INFO "%s:%d conflicting memory types "
-		"%Lx-%Lx %s<->%s\n", current->comm, current->pid, start,
-		end, cattr_name(found_type), cattr_name(match->type));
+	pr_info("x86/PAT: %s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
+		current->comm, current->pid, start, end,
+		cattr_name(found_type), cattr_name(match->type));
 	return -EBUSY;
 }
 
Signature · 1 line
1.9.0.258.g00eda23
#456 lore raw

[tip:x86/mm] x86/mm/pat: Convert to pr_*() usage

x86/mm/pat: Convert to pr_*() usage
Commit-ID:  9e76561f6a8a1a1c4f3152a3fb403ef9d6cfc2ff
Gitweb:     http://git.kernel.org/tip/9e76561f6a8a1a1c4f3152a3fb403ef9d6cfc2ff
Author:     Luis R. Rodriguez <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:11 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:59 +0200

x86/mm/pat: Convert to pr_*() usage

Use pr_info() instead of the old printk to prefix the component where things are coming from. With this readers will know exactly where the message is coming from. We use pr_* helpers but define pr_fmt to the empty string for easier grepping for those error messages.

We leave the users of dprintk() in place, this will print only when the debugpat kernel parameter is enabled. We want to leave those enabled as a debug feature, but also make them use the same prefix.

[ Kill pr_fmt. ]
Cc Andy Lutomirski <[email protected]>
Cc Andy Walls <[email protected]>
Cc Bjorn Helgaas <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Doug Ledford <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Michael S. Tsirkin <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/mm/pat.c          | 44 ++++++++++++++++++++++----------------------
 arch/x86/mm/pat_internal.h |  2 +-
 arch/x86/mm/pat_rbtree.c   |  6 +++---
 3 files changed, 26 insertions(+), 26 deletions(-)
arch/x86/mm/pat.c +22 -22
index 372ad42..8c50b9b 100644
@@ -33,13 +33,16 @@
 #include "pat_internal.h"
 #include "mm_internal.h"
 
+#undef pr_fmt
+#define pr_fmt(fmt) "" fmt
+
 #ifdef CONFIG_X86_PAT
 int __read_mostly pat_enabled = 1;
 
 static inline void pat_disable(const char *reason)
 {
 	pat_enabled = 0;
-	printk(KERN_INFO "%s\n", reason);
+	pr_info("x86/PAT: %s\n", reason);
 }
 
 static int __init nopat(char *str)
@@ -188,7 +191,7 @@ void pat_init_cache_modes(void)
 					   pat_msg + 4 * i);
 		update_cache_mode_entry(i, cache);
 	}
-	pr_info("PAT configuration [0-7]: %s\n", pat_msg);
+	pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg);
 }
 
 #define PAT(x, y)	((u64)PAT_ ## y << ((x)*8))
@@ -211,8 +214,7 @@ void pat_init(void)
 			 * switched to PAT on the boot CPU. We have no way to
 			 * undo PAT.
 			 */
-			printk(KERN_ERR "PAT enabled, "
-			       "but not supported by secondary CPU\n");
+			pr_err("x86/PAT: PAT enabled, but not supported by secondary CPU\n");
 			BUG();
 		}
 	}
@@ -347,7 +349,7 @@ static int reserve_ram_pages_type(u64 start, u64 end,
 		page = pfn_to_page(pfn);
 		type = get_page_memtype(page);
 		if (type != -1) {
-			pr_info("reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
+			pr_info("x86/PAT: reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
 				start, end - 1, type, req_type);
 			if (new_type)
 				*new_type = type;
@@ -451,9 +453,9 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
 
 	err = rbt_memtype_check_insert(new, new_type);
 	if (err) {
-		printk(KERN_INFO "reserve_memtype failed [mem %#010Lx-%#010Lx], track %s, req %s\n",
-		       start, end - 1,
-		       cattr_name(new->type), cattr_name(req_type));
+		pr_info("x86/PAT: reserve_memtype failed [mem %#010Lx-%#010Lx], track %s, req %s\n",
+			start, end - 1,
+			cattr_name(new->type), cattr_name(req_type));
 		kfree(new);
 		spin_unlock(&memtype_lock);
 
@@ -497,8 +499,8 @@ int free_memtype(u64 start, u64 end)
 	spin_unlock(&memtype_lock);
 
 	if (!entry) {
-		printk(KERN_INFO "%s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
-		       current->comm, current->pid, start, end - 1);
+		pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
+			current->comm, current->pid, start, end - 1);
 		return -EINVAL;
 	}
 
@@ -628,8 +630,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 
 	while (cursor < to) {
 		if (!devmem_is_allowed(pfn)) {
-			printk(KERN_INFO "Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
-			       current->comm, from, to - 1);
+			pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
+				current->comm, from, to - 1);
 			return 0;
 		}
 		cursor += PAGE_SIZE;
@@ -698,8 +700,7 @@ int kernel_map_sync_memtype(u64 base, unsigned long size,
 				size;
 
 	if (ioremap_change_attr((unsigned long)__va(base), id_sz, pcm) < 0) {
-		printk(KERN_INFO "%s:%d ioremap_change_attr failed %s "
-			"for [mem %#010Lx-%#010Lx]\n",
+		pr_info("x86/PAT: %s:%d ioremap_change_attr failed %s for [mem %#010Lx-%#010Lx]\n",
 			current->comm, current->pid,
 			cattr_name(pcm),
 			base, (unsigned long long)(base + size-1));
@@ -734,7 +735,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 
 		pcm = lookup_memtype(paddr);
 		if (want_pcm != pcm) {
-			printk(KERN_WARNING "%s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
+			pr_warn("x86/PAT: %s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
 				current->comm, current->pid,
 				cattr_name(want_pcm),
 				(unsigned long long)paddr,
@@ -755,13 +756,12 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 		if (strict_prot ||
 		    !is_new_memtype_allowed(paddr, size, want_pcm, pcm)) {
 			free_memtype(paddr, paddr + size);
-			printk(KERN_ERR "%s:%d map pfn expected mapping type %s"
-				" for [mem %#010Lx-%#010Lx], got %s\n",
-				current->comm, current->pid,
-				cattr_name(want_pcm),
-				(unsigned long long)paddr,
-				(unsigned long long)(paddr + size - 1),
-				cattr_name(pcm));
+			pr_err("x86/PAT: %s:%d map pfn expected mapping type %s for [mem %#010Lx-%#010Lx], got %s\n",
+			       current->comm, current->pid,
+			       cattr_name(want_pcm),
+			       (unsigned long long)paddr,
+			       (unsigned long long)(paddr + size - 1),
+			       cattr_name(pcm));
 			return -EINVAL;
 		}
 		/*
arch/x86/mm/pat_internal.h +1 -1
index f641162..a739bfc 100644
@@ -4,7 +4,7 @@
 extern int pat_debug_enable;
 
 #define dprintk(fmt, arg...) \
-	do { if (pat_debug_enable) printk(KERN_INFO fmt, ##arg); } while (0)
+	do { if (pat_debug_enable) pr_info("x86/PAT: " fmt, ##arg); } while (0)
 
 struct memtype {
 	u64			start;
arch/x86/mm/pat_rbtree.c +3 -3
index 6582adc..6393108 100644
@@ -160,9 +160,9 @@ success:
 	return 0;
 
 failure:
-	printk(KERN_INFO "%s:%d conflicting memory types "
-		"%Lx-%Lx %s<->%s\n", current->comm, current->pid, start,
-		end, cattr_name(found_type), cattr_name(match->type));
+	pr_info("x86/PAT: %s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
+		current->comm, current->pid, start, end,
+		cattr_name(found_type), cattr_name(match->type));
 	return -EBUSY;
 }
 
maintainer
#457 lore raw

PATCH 9/18 x86: Document Write Combining MTRR type effects on PAT / non-PAT pages

In reply to Borislav Petkov

From: "Luis R. Rodriguez" <[email protected]>

As part of the effort to phase out MTRR use document write-combining MTRR effects on pages with different non-PAT page attributes flags and different PAT entry values. Extend arch_phys_wc_add() documentation to clarify power of two sizes / boundary requirements as we phase out mtrr_add() use.

Lastly hint towards ioremap_uc() for corner cases on device drivers working with devices with mixed regions where MTRR size requirements would otherwise not enable write-combining effective memory types.

Cc Jonathan Corbet <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Suresh Siddha <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Antonino Daplas <[email protected]>
Cc Jean-Christophe Plagniol-Villard <[email protected]>
Cc Tomi Valkeinen <[email protected]>
Cc Ville Syrjälä <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Davidlohr Bueso <[email protected]>
---
 Documentation/x86/mtrr.txt      | 18 +++++++++++++++---
 Documentation/x86/pat.txt       | 35 ++++++++++++++++++++++++++++++++++-
 arch/x86/kernel/cpu/mtrr/main.c |  3 +++
 3 files changed, 52 insertions(+), 4 deletions(-)
Documentation/x86/mtrr.txt +15 -3
index cc071dc333c2..860bc3adc223 100644
@@ -1,7 +1,19 @@
 MTRR (Memory Type Range Register) control
-3 Jun 1999
-Richard Gooch
-<[email protected]>
+
+Richard Gooch <[email protected]> - 3 Jun 1999
+Luis R. Rodriguez <[email protected]> - April 9, 2015
+
+===============================================================================
+Phasing out MTRR use
+
+MTRR use is replaced on modern x86 hardware with PAT. Over time the only type
+of effective MTRR that is expected to be supported will be for write-combining.
+As MTRR use is phased out device drivers should use arch_phys_wc_add() to make
+MTRR effective on non-PAT systems while a no-op on PAT enabled systems.
+
+For details refer to Documentation/x86/pat.txt.
+
+===============================================================================
 
   On Intel P6 family processors (Pentium Pro, Pentium II and later)
   the Memory Type Range Registers (MTRRs) may be used to control
Documentation/x86/pat.txt +34 -1
index cf08c9fff3cd..521bd8adc3b8 100644
@@ -34,6 +34,8 @@ ioremap                |    --    |    UC-     |       UC-        |
                        |          |            |                  |
 ioremap_cache          |    --    |    WB      |       WB         |
                        |          |            |                  |
+ioremap_uc             |    --    |    UC      |       UC         |
+                       |          |            |                  |
 ioremap_nocache        |    --    |    UC-     |       UC-        |
                        |          |            |                  |
 ioremap_wc             |    --    |    --      |       WC         |
@@ -102,7 +104,38 @@ wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
 as step 0 above and also track the usage of those pages and use set_memory_wb()
 before the page is freed to free pool.
 
-
+MTRR effects on PAT / non-PAT systems
+-------------------------------------
+
+The following table provides the effects of using write-combining MTRRs when
+using ioremap*() calls on x86 for both non-PAT and PAT systems. Ideally
+mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will
+be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add()
+is made, should already have been ioremapped with WC attributes or PAT entries,
+this can be done by using ioremap_wc() / set_memory_wc().  Devices which
+combine areas of IO memory desired to remain uncacheable with areas where
+write-combining is desirable should consider use of ioremap_uc() followed by
+set_memory_wc() to white-list effective write-combined areas.  Such use is
+nevertheless discouraged as the effective memory type is considered
+implementation defined, yet this strategy can be used as last resort on devices
+with size-constrained regions where otherwise MTRR write-combining would
+otherwise not be effective.
+
+----------------------------------------------------------------------
+MTRR Non-PAT   PAT    Linux ioremap value        Effective memory type
+----------------------------------------------------------------------
+                                                  Non-PAT |  PAT
+     PAT
+     |PCD
+     ||PWT
+     |||
+WC   000      WB      _PAGE_CACHE_MODE_WB            WC   |   WC
+WC   001      WC      _PAGE_CACHE_MODE_WC            WC*  |   WC
+WC   010      UC-     _PAGE_CACHE_MODE_UC_MINUS      WC*  |   UC
+WC   011      UC      _PAGE_CACHE_MODE_UC            UC   |   UC
+----------------------------------------------------------------------
+
+(*) denotes implementation defined and is discouraged
 
 Notes:
 
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index ea5f363a1948..04aceb7e6443 100644
@@ -538,6 +538,9 @@ EXPORT_SYMBOL(mtrr_del);
  * attempts to add a WC MTRR covering size bytes starting at base and
  * logs an error if this fails.
  *
+ * The called should provide a power of two size on an equivalent
+ * power of two boundary.
+ *
  * Drivers must store the return value to pass to mtrr_del_wc_if_needed,
  * but drivers should not try to interpret that return value.
  */
Signature · 1 line
1.9.0.258.g00eda23
#458 lore raw

[tip:x86/mm] x86/mm/mtrr, pat: Document Write Combining MTRR type effects on PAT / non-PAT pages

x86/mm/mtrr, pat: Document Write Combining MTRR type effects on PAT / non-PAT pages
Commit-ID:  2f9e897353fcb99effd6eff22f7b464f8e2a659a
Gitweb:     http://git.kernel.org/tip/2f9e897353fcb99effd6eff22f7b464f8e2a659a
Author:     Luis R. Rodriguez <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:12 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:40:59 +0200

x86/mm/mtrr, pat: Document Write Combining MTRR type effects on PAT / non-PAT pages

As part of the effort to phase out MTRR use document write-combining MTRR effects on pages with different non-PAT page attributes flags and different PAT entry values. Extend arch_phys_wc_add() documentation to clarify power of two sizes / boundary requirements as we phase out mtrr_add() use.

Lastly hint towards ioremap_uc() for corner cases on device drivers working with devices with mixed regions where MTRR size requirements would otherwise not enable write-combining effective memory types.

Cc Andy Lutomirski <[email protected]>
Cc Antonino Daplas <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Jean-Christophe Plagniol-Villard <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Suresh Siddha <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Tomi Valkeinen <[email protected]>
Cc Ville Syrjälä <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 Documentation/x86/mtrr.txt      | 18 +++++++++++++++---
 Documentation/x86/pat.txt       | 35 ++++++++++++++++++++++++++++++++++-
 arch/x86/kernel/cpu/mtrr/main.c |  3 +++
 3 files changed, 52 insertions(+), 4 deletions(-)
Documentation/x86/mtrr.txt +15 -3
index cc071dc..860bc3a 100644
@@ -1,7 +1,19 @@
 MTRR (Memory Type Range Register) control
-3 Jun 1999
-Richard Gooch
-<[email protected]>
+
+Richard Gooch <[email protected]> - 3 Jun 1999
+Luis R. Rodriguez <[email protected]> - April 9, 2015
+
+===============================================================================
+Phasing out MTRR use
+
+MTRR use is replaced on modern x86 hardware with PAT. Over time the only type
+of effective MTRR that is expected to be supported will be for write-combining.
+As MTRR use is phased out device drivers should use arch_phys_wc_add() to make
+MTRR effective on non-PAT systems while a no-op on PAT enabled systems.
+
+For details refer to Documentation/x86/pat.txt.
+
+===============================================================================
 
   On Intel P6 family processors (Pentium Pro, Pentium II and later)
   the Memory Type Range Registers (MTRRs) may be used to control
Documentation/x86/pat.txt +34 -1
index cf08c9f..521bd8a 100644
@@ -34,6 +34,8 @@ ioremap                |    --    |    UC-     |       UC-        |
                        |          |            |                  |
 ioremap_cache          |    --    |    WB      |       WB         |
                        |          |            |                  |
+ioremap_uc             |    --    |    UC      |       UC         |
+                       |          |            |                  |
 ioremap_nocache        |    --    |    UC-     |       UC-        |
                        |          |            |                  |
 ioremap_wc             |    --    |    --      |       WC         |
@@ -102,7 +104,38 @@ wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
 as step 0 above and also track the usage of those pages and use set_memory_wb()
 before the page is freed to free pool.
 
-
+MTRR effects on PAT / non-PAT systems
+-------------------------------------
+
+The following table provides the effects of using write-combining MTRRs when
+using ioremap*() calls on x86 for both non-PAT and PAT systems. Ideally
+mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will
+be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add()
+is made, should already have been ioremapped with WC attributes or PAT entries,
+this can be done by using ioremap_wc() / set_memory_wc().  Devices which
+combine areas of IO memory desired to remain uncacheable with areas where
+write-combining is desirable should consider use of ioremap_uc() followed by
+set_memory_wc() to white-list effective write-combined areas.  Such use is
+nevertheless discouraged as the effective memory type is considered
+implementation defined, yet this strategy can be used as last resort on devices
+with size-constrained regions where otherwise MTRR write-combining would
+otherwise not be effective.
+
+----------------------------------------------------------------------
+MTRR Non-PAT   PAT    Linux ioremap value        Effective memory type
+----------------------------------------------------------------------
+                                                  Non-PAT |  PAT
+     PAT
+     |PCD
+     ||PWT
+     |||
+WC   000      WB      _PAGE_CACHE_MODE_WB            WC   |   WC
+WC   001      WC      _PAGE_CACHE_MODE_WC            WC*  |   WC
+WC   010      UC-     _PAGE_CACHE_MODE_UC_MINUS      WC*  |   UC
+WC   011      UC      _PAGE_CACHE_MODE_UC            UC   |   UC
+----------------------------------------------------------------------
+
+(*) denotes implementation defined and is discouraged
 
 Notes:
 
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index ea5f363..04aceb7 100644
@@ -538,6 +538,9 @@ EXPORT_SYMBOL(mtrr_del);
  * attempts to add a WC MTRR covering size bytes starting at base and
  * logs an error if this fails.
  *
+ * The called should provide a power of two size on an equivalent
+ * power of two boundary.
+ *
  * Drivers must store the return value to pass to mtrr_del_wc_if_needed,
  * but drivers should not try to interpret that return value.
  */
maintainer
#459 lore raw

PATCH 10/18 x86/mtrr: Avoid ifdeffery with phys_wc_to_mtrr_index()

In reply to Borislav Petkov

From: "Luis R. Rodriguez" <[email protected]>

There is only one user but since we're going to bury MTRR next out of access to drivers, expose this last piece of API to drivers in a general fashion only needing io.h for access to helpers.

Cc Toshi Kani <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Will Deacon <[email protected]>
Cc Thierry Reding <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Abhilash Kesavan <[email protected]>
Cc Matthias Brugger <[email protected]>
Cc Cristian Stoica <[email protected]>
Cc Suresh Siddha <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Antonino Daplas <[email protected]>
Cc Jean-Christophe Plagniol-Villard <[email protected]>
Cc Tomi Valkeinen <[email protected]>
Cc Ville Syrjälä <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Davidlohr Bueso <[email protected]>
---
 arch/x86/include/asm/io.h       |  3 +++
 arch/x86/include/asm/mtrr.h     |  5 -----
 arch/x86/kernel/cpu/mtrr/main.c |  6 +++---
 drivers/gpu/drm/drm_ioctl.c     | 14 +-------------
 include/linux/io.h              |  7 +++++++
 5 files changed, 14 insertions(+), 21 deletions(-)
arch/x86/include/asm/io.h +3 -0
index 4afc05ffa566..a2b97404922d 100644
@@ -339,6 +339,9 @@ extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
 #define IO_SPACE_LIMIT 0xffff
 
 #ifdef CONFIG_MTRR
+extern int __must_check arch_phys_wc_index(int handle);
+#define arch_phys_wc_index arch_phys_wc_index
+
 extern int __must_check arch_phys_wc_add(unsigned long base,
 					 unsigned long size);
 extern void arch_phys_wc_del(int handle);
arch/x86/include/asm/mtrr.h +0 -5
index a31759e1edd9..b94f6f64e23d 100644
@@ -48,7 +48,6 @@ extern void mtrr_aps_init(void);
 extern void mtrr_bp_restore(void);
 extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
 extern int amd_special_default_mtrr(void);
-extern int phys_wc_to_mtrr_index(int handle);
 #  else
 static inline u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform)
 {
@@ -84,10 +83,6 @@ static inline int mtrr_trim_uncached_memory(unsigned long end_pfn)
 static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
 {
 }
-static inline int phys_wc_to_mtrr_index(int handle)
-{
-	return -1;
-}
 
 #define mtrr_ap_init() do {} while (0)
 #define mtrr_bp_init() do {} while (0)
arch/x86/kernel/cpu/mtrr/main.c +3 -3
index 04aceb7e6443..81baf5fee0e1 100644
@@ -580,7 +580,7 @@ void arch_phys_wc_del(int handle)
 EXPORT_SYMBOL(arch_phys_wc_del);
 
 /*
- * phys_wc_to_mtrr_index - translates arch_phys_wc_add's return value
+ * arch_phys_wc_index - translates arch_phys_wc_add's return value
  * @handle: Return value from arch_phys_wc_add
  *
  * This will turn the return value from arch_phys_wc_add into an mtrr
@@ -590,14 +590,14 @@ EXPORT_SYMBOL(arch_phys_wc_del);
  * in printk line.  Alas there is an illegitimate use in some ancient
  * drm ioctls.
  */
-int phys_wc_to_mtrr_index(int handle)
+int arch_phys_wc_index(int handle)
 {
 	if (handle < MTRR_TO_PHYS_WC_OFFSET)
 		return -1;
 	else
 		return handle - MTRR_TO_PHYS_WC_OFFSET;
 }
-EXPORT_SYMBOL_GPL(phys_wc_to_mtrr_index);
+EXPORT_SYMBOL_GPL(arch_phys_wc_index);
 
 /*
  * HACK ALERT!
drivers/gpu/drm/drm_ioctl.c +1 -13
index 266dcd6cdf3b..0a957828b3bd 100644
@@ -36,9 +36,6 @@
 
 #include <linux/pci.h>
 #include <linux/export.h>
-#ifdef CONFIG_X86
-#include <asm/mtrr.h>
-#endif
 
 static int drm_version(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv);
@@ -197,16 +194,7 @@ static int drm_getmap(struct drm_device *dev, void *data,
 	map->type = r_list->map->type;
 	map->flags = r_list->map->flags;
 	map->handle = (void *)(unsigned long) r_list->user_token;
-
-#ifdef CONFIG_X86
-	/*
-	 * There appears to be exactly one user of the mtrr index: dritest.
-	 * It's easy enough to keep it working on non-PAT systems.
-	 */
-	map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr);
-#else
-	map->mtrr = -1;
-#endif
+	map->mtrr = arch_phys_wc_index(r_list->map->mtrr);
 
 	mutex_unlock(&dev->struct_mutex);
 
include/linux/io.h +7 -0
index 986f2bffea1e..04cce4da3685 100644
@@ -111,6 +111,13 @@ static inline void arch_phys_wc_del(int handle)
 }
 
 #define arch_phys_wc_add arch_phys_wc_add
+#ifndef arch_phys_wc_index
+static inline int arch_phys_wc_index(int handle)
+{
+	return -1;
+}
+#define arch_phys_wc_index arch_phys_wc_index
+#endif
 #endif
 
 #endif /* _LINUX_IO_H */
Signature · 1 line
1.9.0.258.g00eda23
#460 lore raw

[tip:x86/mm] x86/mm/mtrr: Avoid #ifdeffery with phys_wc_to_mtrr_index()

x86/mm/mtrr: Avoid #ifdeffery with phys_wc_to_mtrr_index()
Commit-ID:  7d010fdf299929f9583ce5e17da629dcd83c36ef
Gitweb:     http://git.kernel.org/tip/7d010fdf299929f9583ce5e17da629dcd83c36ef
Author:     Luis R. Rodriguez <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:13 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:41:00 +0200

x86/mm/mtrr: Avoid #ifdeffery with phys_wc_to_mtrr_index()

There is only one user but since we're going to bury MTRR next out of access to drivers, expose this last piece of API to drivers in a general fashion only needing io.h for access to helpers.

Cc Abhilash Kesavan <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Antonino Daplas <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Cristian Stoica <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Jean-Christophe Plagniol-Villard <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Matthias Brugger <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Suresh Siddha <[email protected]>
Cc Thierry Reding <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Tomi Valkeinen <[email protected]>
Cc Toshi Kani <[email protected]>
Cc Ville Syrjälä <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>
---
 arch/x86/include/asm/io.h       |  3 +++
 arch/x86/include/asm/mtrr.h     |  5 -----
 arch/x86/kernel/cpu/mtrr/main.c |  6 +++---
 drivers/gpu/drm/drm_ioctl.c     | 14 +-------------
 include/linux/io.h              |  7 +++++++
 5 files changed, 14 insertions(+), 21 deletions(-)
arch/x86/include/asm/io.h +3 -0
index 4afc05f..a2b9740 100644
@@ -339,6 +339,9 @@ extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
 #define IO_SPACE_LIMIT 0xffff
 
 #ifdef CONFIG_MTRR
+extern int __must_check arch_phys_wc_index(int handle);
+#define arch_phys_wc_index arch_phys_wc_index
+
 extern int __must_check arch_phys_wc_add(unsigned long base,
 					 unsigned long size);
 extern void arch_phys_wc_del(int handle);
arch/x86/include/asm/mtrr.h +0 -5
index a31759e..b94f6f6 100644
@@ -48,7 +48,6 @@ extern void mtrr_aps_init(void);
 extern void mtrr_bp_restore(void);
 extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
 extern int amd_special_default_mtrr(void);
-extern int phys_wc_to_mtrr_index(int handle);
 #  else
 static inline u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform)
 {
@@ -84,10 +83,6 @@ static inline int mtrr_trim_uncached_memory(unsigned long end_pfn)
 static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
 {
 }
-static inline int phys_wc_to_mtrr_index(int handle)
-{
-	return -1;
-}
 
 #define mtrr_ap_init() do {} while (0)
 #define mtrr_bp_init() do {} while (0)
arch/x86/kernel/cpu/mtrr/main.c +3 -3
index 04aceb7..81baf5f 100644
@@ -580,7 +580,7 @@ void arch_phys_wc_del(int handle)
 EXPORT_SYMBOL(arch_phys_wc_del);
 
 /*
- * phys_wc_to_mtrr_index - translates arch_phys_wc_add's return value
+ * arch_phys_wc_index - translates arch_phys_wc_add's return value
  * @handle: Return value from arch_phys_wc_add
  *
  * This will turn the return value from arch_phys_wc_add into an mtrr
@@ -590,14 +590,14 @@ EXPORT_SYMBOL(arch_phys_wc_del);
  * in printk line.  Alas there is an illegitimate use in some ancient
  * drm ioctls.
  */
-int phys_wc_to_mtrr_index(int handle)
+int arch_phys_wc_index(int handle)
 {
 	if (handle < MTRR_TO_PHYS_WC_OFFSET)
 		return -1;
 	else
 		return handle - MTRR_TO_PHYS_WC_OFFSET;
 }
-EXPORT_SYMBOL_GPL(phys_wc_to_mtrr_index);
+EXPORT_SYMBOL_GPL(arch_phys_wc_index);
 
 /*
  * HACK ALERT!
drivers/gpu/drm/drm_ioctl.c +1 -13
index 266dcd6..0a95782 100644
@@ -36,9 +36,6 @@
 
 #include <linux/pci.h>
 #include <linux/export.h>
-#ifdef CONFIG_X86
-#include <asm/mtrr.h>
-#endif
 
 static int drm_version(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv);
@@ -197,16 +194,7 @@ static int drm_getmap(struct drm_device *dev, void *data,
 	map->type = r_list->map->type;
 	map->flags = r_list->map->flags;
 	map->handle = (void *)(unsigned long) r_list->user_token;
-
-#ifdef CONFIG_X86
-	/*
-	 * There appears to be exactly one user of the mtrr index: dritest.
-	 * It's easy enough to keep it working on non-PAT systems.
-	 */
-	map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr);
-#else
-	map->mtrr = -1;
-#endif
+	map->mtrr = arch_phys_wc_index(r_list->map->mtrr);
 
 	mutex_unlock(&dev->struct_mutex);
 
include/linux/io.h +7 -0
index 986f2bf..04cce4d 100644
@@ -111,6 +111,13 @@ static inline void arch_phys_wc_del(int handle)
 }
 
 #define arch_phys_wc_add arch_phys_wc_add
+#ifndef arch_phys_wc_index
+static inline int arch_phys_wc_index(int handle)
+{
+	return -1;
+}
+#define arch_phys_wc_index arch_phys_wc_index
+#endif
 #endif
 
 #endif /* _LINUX_IO_H */
maintainer
#461 lore raw

PATCH 11/18 x86/mtrr: Generalize runtime disabling of MTRRs

In reply to Borislav Petkov

From: "Luis R. Rodriguez" <[email protected]>

It is possible to enable CONFIG_MTRR and CONFIG_X86_PAT and end up with a system with MTRR functionality disabled but PAT functionality enabled. This can happen, for instance, when the Xen hypervisor is used where MTRRs are not supported but PAT is. This can happen on Linux as of commit

47591df50512 ("xen: Support Xen pv-domains using PAT")

by Juergen, introduced in v3.19.

Technically, we should assume the proper CPU bits would be set to disable MTRRs but we can't always rely on this. At least on the Xen Hypervisor, for instance, only X86_FEATURE_MTRR was disabled as of Xen 4.4 through Xen commit 586ab6a [0], but not X86_FEATURE_K6_MTRR, X86_FEATURE_CENTAUR_MCR, or X86_FEATURE_CYRIX_ARR for instance.

Roger Pau Monné has clarified though that although this is technically true we will never support PVH on these CPU types so Xen has no need to disable these bits on those systems. As per Roger, AMD K6, Centaur and VIA chips don't have the necessary hardware extensions to allow running PVH guests [1].

As per Toshi it is also possible for the BIOS to disable MTRR support, in such cases get_mtrr_state() would update the MTRR state as per the BIOS, we need to propagate this information as well.

x86 MTRR code relies on quite a bit of checks for mtrr_if being set to check to see if MTRRs did get set up. Instead, lets provide a generic getter for that. This also adds a few checks where they were not before which could potentially safeguard ourselves against incorrect usage of MTRR where this was not desirable.

Where possible match error codes as if MTRRs were disabled on arch/x86/include/asm/mtrr.h.

Lastly, since disabling MTRRs can happen at run time and we could end up with PAT enabled, best record now in our logs when MTRRs are disabled.

[0] ~/devel/xen (git::stable-4.5)$ git describe --contains 586ab6a 4.4.0-rc1~18
[1] http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg03460.html

Cc Roger Pau Monné <[email protected]>
Cc Toshi Kani <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Suresh Siddha <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Antonino Daplas <[email protected]>
Cc Jean-Christophe Plagniol-Villard <[email protected]>
Cc Tomi Valkeinen <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Stefan Bader <[email protected]>
Cc Ville Syrjälä <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Davidlohr Bueso <[email protected]>
---
 arch/x86/kernel/cpu/mtrr/generic.c |  4 +++-
 arch/x86/kernel/cpu/mtrr/main.c    | 39 ++++++++++++++++++++++++++++++--------
 arch/x86/kernel/cpu/mtrr/mtrr.h    |  2 +-
 3 files changed, 35 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/mtrr/generic.c +3 -1
index f782d9b62cb3..3b533cf37c74 100644
@@ -445,7 +445,7 @@ static void __init print_mtrr_state(void)
 }
 
 /* Grab all of the MTRR state for this CPU into *state */
-void __init get_mtrr_state(void)
+bool __init get_mtrr_state(void)
 {
 	struct mtrr_var_range *vrs;
 	unsigned long flags;
@@ -489,6 +489,8 @@ void __init get_mtrr_state(void)
 
 	post_set();
 	local_irq_restore(flags);
+
+	return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
 }
 
 /* Some BIOS's are messed up and don't set all MTRRs the same! */
arch/x86/kernel/cpu/mtrr/main.c +31 -8
index 81baf5fee0e1..383efb26e516 100644
@@ -59,6 +59,12 @@
 #define MTRR_TO_PHYS_WC_OFFSET 1000
 
 u32 num_var_ranges;
+static bool __mtrr_enabled;
+
+static bool mtrr_enabled(void)
+{
+	return __mtrr_enabled;
+}
 
 unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
 static DEFINE_MUTEX(mtrr_mutex);
@@ -286,7 +292,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
 	int i, replace, error;
 	mtrr_type ltype;
 
-	if (!mtrr_if)
+	if (!mtrr_enabled())
 		return -ENXIO;
 
 	error = mtrr_if->validate_add_page(base, size, type);
@@ -435,6 +441,8 @@ static int mtrr_check(unsigned long base, unsigned long size)
 int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
 	     bool increment)
 {
+	if (!mtrr_enabled())
+		return -ENODEV;
 	if (mtrr_check(base, size))
 		return -EINVAL;
 	return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
@@ -463,8 +471,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
 	unsigned long lbase, lsize;
 	int error = -EINVAL;
 
-	if (!mtrr_if)
-		return -ENXIO;
+	if (!mtrr_enabled())
+		return -ENODEV;
 
 	max = num_var_ranges;
 	/* No CPU hotplug when we change MTRR entries */
@@ -523,6 +531,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
  */
 int mtrr_del(int reg, unsigned long base, unsigned long size)
 {
+	if (!mtrr_enabled())
+		return -ENODEV;
 	if (mtrr_check(base, size))
 		return -EINVAL;
 	return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
@@ -548,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
 {
 	int ret;
 
-	if (pat_enabled)
+	if (pat_enabled || !mtrr_enabled())
 		return 0;  /* Success!  (We don't need to do anything.) */
 
 	ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
@@ -737,10 +747,12 @@ void __init mtrr_bp_init(void)
 	}
 
 	if (mtrr_if) {
+		__mtrr_enabled = true;
 		set_num_var_ranges();
 		init_table();
 		if (use_intel()) {
-			get_mtrr_state();
+			/* BIOS may override */
+			__mtrr_enabled = get_mtrr_state();
 
 			if (mtrr_cleanup(phys_addr)) {
 				changed_by_mtrr_cleanup = 1;
@@ -748,10 +760,16 @@ void __init mtrr_bp_init(void)
 			}
 		}
 	}
+
+	if (!mtrr_enabled())
+		pr_info("MTRR: Disabled\n");
 }
 
 void mtrr_ap_init(void)
 {
+	if (!mtrr_enabled())
+		return;
+
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
 	/*
@@ -777,6 +795,9 @@ void mtrr_save_state(void)
 {
 	int first_cpu;
 
+	if (!mtrr_enabled())
+		return;
+
 	get_online_cpus();
 	first_cpu = cpumask_first(cpu_online_mask);
 	smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
@@ -785,6 +806,8 @@ void mtrr_save_state(void)
 
 void set_mtrr_aps_delayed_init(void)
 {
+	if (!mtrr_enabled())
+		return;
 	if (!use_intel())
 		return;
 
@@ -796,7 +819,7 @@ void set_mtrr_aps_delayed_init(void)
  */
 void mtrr_aps_init(void)
 {
-	if (!use_intel())
+	if (!use_intel() || !mtrr_enabled())
 		return;
 
 	/*
@@ -813,7 +836,7 @@ void mtrr_aps_init(void)
 
 void mtrr_bp_restore(void)
 {
-	if (!use_intel())
+	if (!use_intel() || !mtrr_enabled())
 		return;
 
 	mtrr_if->set_all();
@@ -821,7 +844,7 @@ void mtrr_bp_restore(void)
 
 static int __init mtrr_init_finialize(void)
 {
-	if (!mtrr_if)
+	if (!mtrr_enabled())
 		return 0;
 
 	if (use_intel()) {
arch/x86/kernel/cpu/mtrr/mtrr.h +1 -1
index df5e41f31a27..951884dcc433 100644
@@ -51,7 +51,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
 
 void fill_mtrr_var_range(unsigned int index,
 		u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
-void get_mtrr_state(void);
+bool get_mtrr_state(void);
 
 extern void set_mtrr_ops(const struct mtrr_ops *ops);
 
Signature · 1 line
1.9.0.258.g00eda23
#462 lore raw

[tip:x86/mm] x86/mm/mtrr: Generalize runtime disabling of MTRRs

x86/mm/mtrr: Generalize runtime disabling of MTRRs
Commit-ID:  f9626104a5b6815ec7d65789dfb900af5fa51e64
Gitweb:     http://git.kernel.org/tip/f9626104a5b6815ec7d65789dfb900af5fa51e64
Author:     Luis R. Rodriguez <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:14 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:41:01 +0200

x86/mm/mtrr: Generalize runtime disabling of MTRRs

It is possible to enable CONFIG_MTRR and CONFIG_X86_PAT and end up with a system with MTRR functionality disabled but PAT functionality enabled. This can happen, for instance, when the Xen hypervisor is used where MTRRs are not supported but PAT is. This can happen on Linux as of commit

47591df50512 ("xen: Support Xen pv-domains using PAT")

by Juergen, introduced in v3.19.

Technically, we should assume the proper CPU bits would be set to disable MTRRs but we can't always rely on this. At least on the Xen Hypervisor, for instance, only X86_FEATURE_MTRR was disabled as of Xen 4.4 through Xen commit 586ab6a [0], but not X86_FEATURE_K6_MTRR, X86_FEATURE_CENTAUR_MCR, or X86_FEATURE_CYRIX_ARR for instance.

Roger Pau Monné has clarified though that although this is technically true we will never support PVH on these CPU types so Xen has no need to disable these bits on those systems. As per Roger, AMD K6, Centaur and VIA chips don't have the necessary hardware extensions to allow running PVH guests [1].

As per Toshi it is also possible for the BIOS to disable MTRR support, in such cases get_mtrr_state() would update the MTRR state as per the BIOS, we need to propagate this information as well.

x86 MTRR code relies on quite a bit of checks for mtrr_if being set to check to see if MTRRs did get set up. Instead, lets provide a generic getter for that. This also adds a few checks where they were not before which could potentially safeguard ourselves against incorrect usage of MTRR where this was not desirable.

Where possible match error codes as if MTRRs were disabled on arch/x86/include/asm/mtrr.h.

Lastly, since disabling MTRRs can happen at run time and we could end up with PAT enabled, best record now in our logs when MTRRs are disabled.

[0] ~/devel/xen (git::stable-4.5)$ git describe --contains 586ab6a 4.4.0-rc1~18
[1] http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg03460.html

Cc Andy Lutomirski <[email protected]>
Cc Antonino Daplas <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Davidlohr Bueso <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Jean-Christophe Plagniol-Villard <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Roger Pau Monné <[email protected]>
Cc Stefan Bader <[email protected]>
Cc Suresh Siddha <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Tomi Valkeinen <[email protected]>
Cc Toshi Kani <[email protected]>
Cc Ville Syrjälä <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 arch/x86/kernel/cpu/mtrr/generic.c |  4 +++-
 arch/x86/kernel/cpu/mtrr/main.c    | 39 ++++++++++++++++++++++++++++++--------
 arch/x86/kernel/cpu/mtrr/mtrr.h    |  2 +-
 3 files changed, 35 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/mtrr/generic.c +3 -1
index f782d9b..3b533cf 100644
@@ -445,7 +445,7 @@ static void __init print_mtrr_state(void)
 }
 
 /* Grab all of the MTRR state for this CPU into *state */
-void __init get_mtrr_state(void)
+bool __init get_mtrr_state(void)
 {
 	struct mtrr_var_range *vrs;
 	unsigned long flags;
@@ -489,6 +489,8 @@ void __init get_mtrr_state(void)
 
 	post_set();
 	local_irq_restore(flags);
+
+	return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
 }
 
 /* Some BIOS's are messed up and don't set all MTRRs the same! */
arch/x86/kernel/cpu/mtrr/main.c +31 -8
index 81baf5f..383efb2 100644
@@ -59,6 +59,12 @@
 #define MTRR_TO_PHYS_WC_OFFSET 1000
 
 u32 num_var_ranges;
+static bool __mtrr_enabled;
+
+static bool mtrr_enabled(void)
+{
+	return __mtrr_enabled;
+}
 
 unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
 static DEFINE_MUTEX(mtrr_mutex);
@@ -286,7 +292,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
 	int i, replace, error;
 	mtrr_type ltype;
 
-	if (!mtrr_if)
+	if (!mtrr_enabled())
 		return -ENXIO;
 
 	error = mtrr_if->validate_add_page(base, size, type);
@@ -435,6 +441,8 @@ static int mtrr_check(unsigned long base, unsigned long size)
 int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
 	     bool increment)
 {
+	if (!mtrr_enabled())
+		return -ENODEV;
 	if (mtrr_check(base, size))
 		return -EINVAL;
 	return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
@@ -463,8 +471,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
 	unsigned long lbase, lsize;
 	int error = -EINVAL;
 
-	if (!mtrr_if)
-		return -ENXIO;
+	if (!mtrr_enabled())
+		return -ENODEV;
 
 	max = num_var_ranges;
 	/* No CPU hotplug when we change MTRR entries */
@@ -523,6 +531,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
  */
 int mtrr_del(int reg, unsigned long base, unsigned long size)
 {
+	if (!mtrr_enabled())
+		return -ENODEV;
 	if (mtrr_check(base, size))
 		return -EINVAL;
 	return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
@@ -548,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
 {
 	int ret;
 
-	if (pat_enabled)
+	if (pat_enabled || !mtrr_enabled())
 		return 0;  /* Success!  (We don't need to do anything.) */
 
 	ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
@@ -737,10 +747,12 @@ void __init mtrr_bp_init(void)
 	}
 
 	if (mtrr_if) {
+		__mtrr_enabled = true;
 		set_num_var_ranges();
 		init_table();
 		if (use_intel()) {
-			get_mtrr_state();
+			/* BIOS may override */
+			__mtrr_enabled = get_mtrr_state();
 
 			if (mtrr_cleanup(phys_addr)) {
 				changed_by_mtrr_cleanup = 1;
@@ -748,10 +760,16 @@ void __init mtrr_bp_init(void)
 			}
 		}
 	}
+
+	if (!mtrr_enabled())
+		pr_info("MTRR: Disabled\n");
 }
 
 void mtrr_ap_init(void)
 {
+	if (!mtrr_enabled())
+		return;
+
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
 	/*
@@ -777,6 +795,9 @@ void mtrr_save_state(void)
 {
 	int first_cpu;
 
+	if (!mtrr_enabled())
+		return;
+
 	get_online_cpus();
 	first_cpu = cpumask_first(cpu_online_mask);
 	smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
@@ -785,6 +806,8 @@ void mtrr_save_state(void)
 
 void set_mtrr_aps_delayed_init(void)
 {
+	if (!mtrr_enabled())
+		return;
 	if (!use_intel())
 		return;
 
@@ -796,7 +819,7 @@ void set_mtrr_aps_delayed_init(void)
  */
 void mtrr_aps_init(void)
 {
-	if (!use_intel())
+	if (!use_intel() || !mtrr_enabled())
 		return;
 
 	/*
@@ -813,7 +836,7 @@ void mtrr_aps_init(void)
 
 void mtrr_bp_restore(void)
 {
-	if (!use_intel())
+	if (!use_intel() || !mtrr_enabled())
 		return;
 
 	mtrr_if->set_all();
@@ -821,7 +844,7 @@ void mtrr_bp_restore(void)
 
 static int __init mtrr_init_finialize(void)
 {
-	if (!mtrr_if)
+	if (!mtrr_enabled())
 		return 0;
 
 	if (use_intel()) {
arch/x86/kernel/cpu/mtrr/mtrr.h +1 -1
index df5e41f..951884d 100644
@@ -51,7 +51,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
 
 void fill_mtrr_var_range(unsigned int index,
 		u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
-void get_mtrr_state(void);
+bool get_mtrr_state(void);
 
 extern void set_mtrr_ops(const struct mtrr_ops *ops);
 
maintainer
#463 lore raw

PATCH 12/18 x86/mm/pat: Wrap pat_enabled

In reply to Borislav Petkov

From: "Luis R. Rodriguez" <[email protected]>

We use pat_enabled in x86-specific code to see if PAT is enabled or not but we're granting full access to it even though readers do not need to set it. If, for instance, we granted access to it to modules later they then could override the variable setting... no bueno.

This renames pat_enabled to a new static variable __pat_enabled. Folks are redirected to use pat_enabled() now.

Code that sets this can only be internal to pat.c. Apart from the early kernel parameter "nopat" to disable PAT, we also have a few cases that disable it later and make use of a helper pat_disable(). It is wrapped under an ifdef but since that code cannot run unless PAT was enabled its not required to wrap it with ifdefs, unwrap that. Likewise, since "nopat" doesn't really change non-PAT systems just remove that ifdef as well.

Although we could add and use an early_param_off(), these helpers don't use __read_mostly but we want to keep __read_mostly for __pat_enabled as this is a hot path -- upon boot, for instance, a simple guest may see ~4k accesses to pat_enabled(). Since __read_mostly early boot params are not that common we don't add a helper for them just yet.

Cc Christoph Lameter <[email protected]>
Cc Kyle McMartin <[email protected]>
Cc Andy Walls <[email protected]>
Cc Doug Ledford <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Bjorn Helgaas <[email protected]>
Cc Michael S. Tsirkin <[email protected]>
---
 arch/x86/include/asm/pat.h      |  7 +------
 arch/x86/kernel/cpu/mtrr/main.c |  2 +-
 arch/x86/mm/iomap_32.c          |  2 +-
 arch/x86/mm/ioremap.c           |  4 ++--
 arch/x86/mm/pageattr.c          |  2 +-
 arch/x86/mm/pat.c               | 33 +++++++++++++++------------------
 arch/x86/pci/i386.c             |  6 +++---
 7 files changed, 24 insertions(+), 32 deletions(-)
arch/x86/include/asm/pat.h +1 -6
index 91bc4ba95f91..cdcff7f7f694 100644
@@ -4,12 +4,7 @@
 #include <linux/types.h>
 #include <asm/pgtable_types.h>
 
-#ifdef CONFIG_X86_PAT
-extern int pat_enabled;
-#else
-static const int pat_enabled;
-#endif
-
+bool pat_enabled(void);
 extern void pat_init(void);
 void pat_init_cache_modes(void);
 
arch/x86/kernel/cpu/mtrr/main.c +1 -1
index 383efb26e516..e7ed0d8ebacb 100644
@@ -558,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
 {
 	int ret;
 
-	if (pat_enabled || !mtrr_enabled())
+	if (pat_enabled() || !mtrr_enabled())
 		return 0;  /* Success!  (We don't need to do anything.) */
 
 	ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
arch/x86/mm/iomap_32.c +1 -1
index 9ca35fc60cfe..3a2ec8790ca7 100644
@@ -82,7 +82,7 @@ iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 	 * MTRR is UC or WC.  UC_MINUS gets the real intention, of the
 	 * user, which is "WC if the MTRR is WC, UC if you can't do that."
 	 */
-	if (!pat_enabled && pgprot_val(prot) ==
+	if (!pat_enabled() && pgprot_val(prot) ==
 	    (__PAGE_KERNEL | cachemode2protval(_PAGE_CACHE_MODE_WC)))
 		prot = __pgprot(__PAGE_KERNEL |
 				cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS));
arch/x86/mm/ioremap.c +2 -2
index a493bb83aa89..82d63ed70045 100644
@@ -234,7 +234,7 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
 {
 	/*
 	 * Ideally, this should be:
-	 *	pat_enabled ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
+	 *	pat_enabled() ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
 	 *
 	 * Till we fix all X drivers to use ioremap_wc(), we will use
 	 * UC MINUS. Drivers that are certain they need or can already
@@ -292,7 +292,7 @@ EXPORT_SYMBOL_GPL(ioremap_uc);
  */
 void __iomem *ioremap_wc(resource_size_t phys_addr, unsigned long size)
 {
-	if (pat_enabled)
+	if (pat_enabled())
 		return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WC,
 					__builtin_return_address(0));
 	else
arch/x86/mm/pageattr.c +1 -1
index 397838eb292b..70d221fe2eb4 100644
@@ -1571,7 +1571,7 @@ int set_memory_wc(unsigned long addr, int numpages)
 {
 	int ret;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return set_memory_uc(addr, numpages);
 
 	ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
arch/x86/mm/pat.c +15 -18
index 8c50b9bfa996..484dce7f759b 100644
@@ -36,12 +36,11 @@
 #undef pr_fmt
 #define pr_fmt(fmt) "" fmt
 
-#ifdef CONFIG_X86_PAT
-int __read_mostly pat_enabled = 1;
+static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
 
 static inline void pat_disable(const char *reason)
 {
-	pat_enabled = 0;
+	__pat_enabled = 0;
 	pr_info("x86/PAT: %s\n", reason);
 }
 
@@ -51,13 +50,11 @@ static int __init nopat(char *str)
 	return 0;
 }
 early_param("nopat", nopat);
-#else
-static inline void pat_disable(const char *reason)
+
+bool pat_enabled(void)
 {
-	(void)reason;
+	return !!__pat_enabled;
 }
-#endif
-
 
 int pat_debug_enable;
 
@@ -201,7 +198,7 @@ void pat_init(void)
 	u64 pat;
 	bool boot_cpu = !boot_pat_state;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return;
 
 	if (!cpu_has_pat) {
@@ -402,7 +399,7 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
 
 	BUG_ON(start >= end); /* end is exclusive */
 
-	if (!pat_enabled) {
+	if (!pat_enabled()) {
 		/* This is identical to page table setting without PAT */
 		if (new_type) {
 			if (req_type == _PAGE_CACHE_MODE_WC)
@@ -477,7 +474,7 @@ int free_memtype(u64 start, u64 end)
 	int is_range_ram;
 	struct memtype *entry;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 0;
 
 	/* Low ISA region is always mapped WB. No need to track */
@@ -625,7 +622,7 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 	u64 to = from + size;
 	u64 cursor = from;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 1;
 
 	while (cursor < to) {
@@ -661,7 +658,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
 	 * caching for the high addresses through the KEN pin, but
 	 * we maintain the tradition of paranoia in this code.
 	 */
-	if (!pat_enabled &&
+	if (!pat_enabled() &&
 	    !(boot_cpu_has(X86_FEATURE_MTRR) ||
 	      boot_cpu_has(X86_FEATURE_K6_MTRR) ||
 	      boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
@@ -730,7 +727,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 	 * the type requested matches the type of first page in the range.
 	 */
 	if (is_ram) {
-		if (!pat_enabled)
+		if (!pat_enabled())
 			return 0;
 
 		pcm = lookup_memtype(paddr);
@@ -844,7 +841,7 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
 		return ret;
 	}
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 0;
 
 	/*
@@ -872,7 +869,7 @@ int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
 {
 	enum page_cache_mode pcm;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 0;
 
 	/* Set prot based on lookup */
@@ -913,7 +910,7 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
 
 pgprot_t pgprot_writecombine(pgprot_t prot)
 {
-	if (pat_enabled)
+	if (pat_enabled())
 		return __pgprot(pgprot_val(prot) |
 				cachemode2protval(_PAGE_CACHE_MODE_WC));
 	else
@@ -996,7 +993,7 @@ static const struct file_operations memtype_fops = {
 
 static int __init pat_memtype_list_init(void)
 {
-	if (pat_enabled) {
+	if (pat_enabled()) {
 		debugfs_create_file("pat_memtype_list", S_IRUSR,
 				    arch_debugfs_dir, NULL, &memtype_fops);
 	}
arch/x86/pci/i386.c +3 -3
index 349c0d32cc0b..0a9f2caf358f 100644
@@ -429,12 +429,12 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
  	 * Caller can followup with UC MINUS request and add a WC mtrr if there
  	 * is a free mtrr slot.
  	 */
-	if (!pat_enabled && write_combine)
+	if (!pat_enabled() && write_combine)
 		return -EINVAL;
 
-	if (pat_enabled && write_combine)
+	if (pat_enabled() && write_combine)
 		prot |= cachemode2protval(_PAGE_CACHE_MODE_WC);
-	else if (pat_enabled || boot_cpu_data.x86 > 3)
+	else if (pat_enabled() || boot_cpu_data.x86 > 3)
 		/*
 		 * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
 		 * To avoid attribute conflicts, request UC MINUS here
Signature · 1 line
1.9.0.258.g00eda23
#464 lore raw

[tip:x86/mm] x86/mm/pat: Wrap pat_enabled into a function API

x86/mm/pat: Wrap pat_enabled into a function API
Commit-ID:  cb32edf65bf2197a2d2226e94c7602dc92e295bb
Gitweb:     http://git.kernel.org/tip/cb32edf65bf2197a2d2226e94c7602dc92e295bb
Author:     Luis R. Rodriguez <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:15 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:41:01 +0200

x86/mm/pat: Wrap pat_enabled into a function API

We use pat_enabled in x86-specific code to see if PAT is enabled or not but we're granting full access to it even though readers do not need to set it. If, for instance, we granted access to it to modules later they then could override the variable setting... no bueno.

This renames pat_enabled to a new static variable __pat_enabled. Folks are redirected to use pat_enabled() now.

Code that sets this can only be internal to pat.c. Apart from the early kernel parameter "nopat" to disable PAT, we also have a few cases that disable it later and make use of a helper pat_disable(). It is wrapped under an ifdef but since that code cannot run unless PAT was enabled its not required to wrap it with ifdefs, unwrap that. Likewise, since "nopat" doesn't really change non-PAT systems just remove that ifdef as well.

Although we could add and use an early_param_off(), these helpers don't use __read_mostly but we want to keep __read_mostly for __pat_enabled as this is a hot path -- upon boot, for instance, a simple guest may see ~4k accesses to pat_enabled(). Since __read_mostly early boot params are not that common we don't add a helper for them just yet.

Cc Andy Lutomirski <[email protected]>
Cc Andy Walls <[email protected]>
Cc Bjorn Helgaas <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Doug Ledford <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Kyle McMartin <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Michael S. Tsirkin <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/include/asm/pat.h      |  7 +------
 arch/x86/kernel/cpu/mtrr/main.c |  2 +-
 arch/x86/mm/iomap_32.c          |  2 +-
 arch/x86/mm/ioremap.c           |  4 ++--
 arch/x86/mm/pageattr.c          |  2 +-
 arch/x86/mm/pat.c               | 33 +++++++++++++++------------------
 arch/x86/pci/i386.c             |  6 +++---
 7 files changed, 24 insertions(+), 32 deletions(-)
arch/x86/include/asm/pat.h +1 -6
index 91bc4ba..cdcff7f 100644
@@ -4,12 +4,7 @@
 #include <linux/types.h>
 #include <asm/pgtable_types.h>
 
-#ifdef CONFIG_X86_PAT
-extern int pat_enabled;
-#else
-static const int pat_enabled;
-#endif
-
+bool pat_enabled(void);
 extern void pat_init(void);
 void pat_init_cache_modes(void);
 
arch/x86/kernel/cpu/mtrr/main.c +1 -1
index 383efb2..e7ed0d8 100644
@@ -558,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
 {
 	int ret;
 
-	if (pat_enabled || !mtrr_enabled())
+	if (pat_enabled() || !mtrr_enabled())
 		return 0;  /* Success!  (We don't need to do anything.) */
 
 	ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
arch/x86/mm/iomap_32.c +1 -1
index 9ca35fc..3a2ec87 100644
@@ -82,7 +82,7 @@ iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 	 * MTRR is UC or WC.  UC_MINUS gets the real intention, of the
 	 * user, which is "WC if the MTRR is WC, UC if you can't do that."
 	 */
-	if (!pat_enabled && pgprot_val(prot) ==
+	if (!pat_enabled() && pgprot_val(prot) ==
 	    (__PAGE_KERNEL | cachemode2protval(_PAGE_CACHE_MODE_WC)))
 		prot = __pgprot(__PAGE_KERNEL |
 				cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS));
arch/x86/mm/ioremap.c +2 -2
index a493bb8..82d63ed 100644
@@ -234,7 +234,7 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
 {
 	/*
 	 * Ideally, this should be:
-	 *	pat_enabled ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
+	 *	pat_enabled() ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
 	 *
 	 * Till we fix all X drivers to use ioremap_wc(), we will use
 	 * UC MINUS. Drivers that are certain they need or can already
@@ -292,7 +292,7 @@ EXPORT_SYMBOL_GPL(ioremap_uc);
  */
 void __iomem *ioremap_wc(resource_size_t phys_addr, unsigned long size)
 {
-	if (pat_enabled)
+	if (pat_enabled())
 		return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WC,
 					__builtin_return_address(0));
 	else
arch/x86/mm/pageattr.c +1 -1
index 397838e..70d221f 100644
@@ -1571,7 +1571,7 @@ int set_memory_wc(unsigned long addr, int numpages)
 {
 	int ret;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return set_memory_uc(addr, numpages);
 
 	ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
arch/x86/mm/pat.c +15 -18
index 8c50b9b..484dce7 100644
@@ -36,12 +36,11 @@
 #undef pr_fmt
 #define pr_fmt(fmt) "" fmt
 
-#ifdef CONFIG_X86_PAT
-int __read_mostly pat_enabled = 1;
+static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
 
 static inline void pat_disable(const char *reason)
 {
-	pat_enabled = 0;
+	__pat_enabled = 0;
 	pr_info("x86/PAT: %s\n", reason);
 }
 
@@ -51,13 +50,11 @@ static int __init nopat(char *str)
 	return 0;
 }
 early_param("nopat", nopat);
-#else
-static inline void pat_disable(const char *reason)
+
+bool pat_enabled(void)
 {
-	(void)reason;
+	return !!__pat_enabled;
 }
-#endif
-
 
 int pat_debug_enable;
 
@@ -201,7 +198,7 @@ void pat_init(void)
 	u64 pat;
 	bool boot_cpu = !boot_pat_state;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return;
 
 	if (!cpu_has_pat) {
@@ -402,7 +399,7 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
 
 	BUG_ON(start >= end); /* end is exclusive */
 
-	if (!pat_enabled) {
+	if (!pat_enabled()) {
 		/* This is identical to page table setting without PAT */
 		if (new_type) {
 			if (req_type == _PAGE_CACHE_MODE_WC)
@@ -477,7 +474,7 @@ int free_memtype(u64 start, u64 end)
 	int is_range_ram;
 	struct memtype *entry;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 0;
 
 	/* Low ISA region is always mapped WB. No need to track */
@@ -625,7 +622,7 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 	u64 to = from + size;
 	u64 cursor = from;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 1;
 
 	while (cursor < to) {
@@ -661,7 +658,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
 	 * caching for the high addresses through the KEN pin, but
 	 * we maintain the tradition of paranoia in this code.
 	 */
-	if (!pat_enabled &&
+	if (!pat_enabled() &&
 	    !(boot_cpu_has(X86_FEATURE_MTRR) ||
 	      boot_cpu_has(X86_FEATURE_K6_MTRR) ||
 	      boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
@@ -730,7 +727,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 	 * the type requested matches the type of first page in the range.
 	 */
 	if (is_ram) {
-		if (!pat_enabled)
+		if (!pat_enabled())
 			return 0;
 
 		pcm = lookup_memtype(paddr);
@@ -844,7 +841,7 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
 		return ret;
 	}
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 0;
 
 	/*
@@ -872,7 +869,7 @@ int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
 {
 	enum page_cache_mode pcm;
 
-	if (!pat_enabled)
+	if (!pat_enabled())
 		return 0;
 
 	/* Set prot based on lookup */
@@ -913,7 +910,7 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
 
 pgprot_t pgprot_writecombine(pgprot_t prot)
 {
-	if (pat_enabled)
+	if (pat_enabled())
 		return __pgprot(pgprot_val(prot) |
 				cachemode2protval(_PAGE_CACHE_MODE_WC));
 	else
@@ -996,7 +993,7 @@ static const struct file_operations memtype_fops = {
 
 static int __init pat_memtype_list_init(void)
 {
-	if (pat_enabled) {
+	if (pat_enabled()) {
 		debugfs_create_file("pat_memtype_list", S_IRUSR,
 				    arch_debugfs_dir, NULL, &memtype_fops);
 	}
arch/x86/pci/i386.c +3 -3
index 349c0d3..0a9f2ca 100644
@@ -429,12 +429,12 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
  	 * Caller can followup with UC MINUS request and add a WC mtrr if there
  	 * is a free mtrr slot.
  	 */
-	if (!pat_enabled && write_combine)
+	if (!pat_enabled() && write_combine)
 		return -EINVAL;
 
-	if (pat_enabled && write_combine)
+	if (pat_enabled() && write_combine)
 		prot |= cachemode2protval(_PAGE_CACHE_MODE_WC);
-	else if (pat_enabled || boot_cpu_data.x86 > 3)
+	else if (pat_enabled() || boot_cpu_data.x86 > 3)
 		/*
 		 * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
 		 * To avoid attribute conflicts, request UC MINUS here
maintainer
#465 lore raw

PATCH 13/18 x86/mm/pat: Export pat_enabled()

In reply to Borislav Petkov

From: "Luis R. Rodriguez" <[email protected]>

Two Linux device drivers cannot work with PAT and the work required to make them work is significant. There is not enough motivation to convert these drivers over to use PAT properly, the compromise reached is to let drivers that cannot be ported to PAT check if PAT was enabled and if so fail on probe with a recommendation to boot with the "nopat" kernel parameter.

Cc Andy Walls <[email protected]>
Cc Doug Ledford <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Bjorn Helgaas <[email protected]>
Cc Michael S. Tsirkin <[email protected]>
---
 arch/x86/mm/pat.c | 1 +
 1 file changed, 1 insertion(+)
arch/x86/mm/pat.c +1 -0
index 484dce7f759b..a1c96544099d 100644
@@ -55,6 +55,7 @@ bool pat_enabled(void)
 {
 	return !!__pat_enabled;
 }
+EXPORT_SYMBOL_GPL(pat_enabled);
 
 int pat_debug_enable;
 
Signature · 1 line
1.9.0.258.g00eda23
#466 lore raw

[tip:x86/mm] x86/mm/pat: Export pat_enabled()

x86/mm/pat: Export pat_enabled()
Commit-ID:  fbe7193aa4787f27c84216d130ab877efc310d57
Gitweb:     http://git.kernel.org/tip/fbe7193aa4787f27c84216d130ab877efc310d57
Author:     Luis R. Rodriguez <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:16 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:41:02 +0200

x86/mm/pat: Export pat_enabled()

Two Linux device drivers cannot work with PAT and the work required to make them work is significant. There is not enough motivation to convert these drivers over to use PAT properly, the compromise reached is to let drivers that cannot be ported to PAT check if PAT was enabled and if so fail on probe with a recommendation to boot with the "nopat" kernel parameter.

Cc Andy Lutomirski <[email protected]>
Cc Andy Walls <[email protected]>
Cc Bjorn Helgaas <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Daniel Vetter <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Doug Ledford <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Juergen Gross <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Michael S. Tsirkin <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/mm/pat.c | 1 +
 1 file changed, 1 insertion(+)
arch/x86/mm/pat.c +1 -0
index 484dce7..a1c9654 100644
@@ -55,6 +55,7 @@ bool pat_enabled(void)
 {
 	return !!__pat_enabled;
 }
+EXPORT_SYMBOL_GPL(pat_enabled);
 
 int pat_debug_enable;
 
maintainer
#467 lore raw

PATCH 14/18 x86/cpu: Strip any /proc/cpuinfo model name field whitespace

In reply to Borislav Petkov

From: Prarit Bhargava <[email protected]>

When comparing the 'model name' field of each core in /proc/cpuinfo it was noticed that there is a whitespace difference between the cores' model names.

After some quick investigation it was noticed that the model name fields were actually different -- processor 0's model name field had trailing whitespace removed, while the other processors did not.

Another way of seeing this behaviour is to convert spaces into underscores in the output of /proc/cpuinfo,

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

which shows the discrepancy.

This occurs because the kernel calls strim() on cpu 0's x86_model_id field to output a pretty message to the console in print_cpu_info(), and as a result strips the whitespace at the end of the ->x86_model_id field.

But, the ->x86_model_id field should be the same for the all identical CPUs in the box. Thus, we need to remove both leading and trailing whitespace.

As a result, the print_cpu_info() output looks like

smpboot: CPU0: AMD Opteron(TM) Processor 6272 (fam: 15, model: 01, stepping: 02)

and the x86_model_id field is correct on all processors on AMD platforms:

_____64_model_name :_AMD_Opteron(TM)_Processor_6272

Output is still correct on an Intel box:

____144_model_name :_Intel(R)_Xeon(R)_CPU_E7-8890_v3_@_2.50GHz

Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc Brian Gerst <[email protected]>
---
 arch/x86/kernel/cpu/common.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/common.c +4 -13
index a62cf04dac8a..41a8e9cb30bc 100644
@@ -419,7 +419,6 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
-	char *p, *q;
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	c->x86_model_id[48] = 0;
 
 	/*
-	 * Intel chips right-justify this string for some dumb reason;
-	 * undo that brain damage:
+	 * Remove leading whitespace on Intel processors and trailing
+	 * whitespace on AMD processors.
 	 */
-	p = q = &c->x86_model_id[0];
-	while (*p == ' ')
-		p++;
-	if (p != q) {
-		while (*p)
-			*q++ = *p++;
-		while (q <= &c->x86_model_id[48])
-			*q++ = '\0';	/* Zero-pad the rest */
-	}
+	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
@@ -1122,7 +1113,7 @@ void print_cpu_info(struct cpuinfo_x86 *c)
 		printk(KERN_CONT "%s ", vendor);
 
 	if (c->x86_model_id[0])
-		printk(KERN_CONT "%s", strim(c->x86_model_id));
+		printk(KERN_CONT "%s", c->x86_model_id);
 	else
 		printk(KERN_CONT "%d86", c->x86);
 
Signature · 1 line
1.9.0.258.g00eda23
#468 lore raw

[tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

x86/cpu: Strip any /proc/cpuinfo model name field whitespace
Commit-ID:  adafb98da6a7af5e45362933a7dae6ab0e5076bf
Gitweb:     http://git.kernel.org/tip/adafb98da6a7af5e45362933a7dae6ab0e5076bf
Author:     Prarit Bhargava <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:17 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:38:24 +0200

x86/cpu: Strip any /proc/cpuinfo model name field whitespace

When comparing the 'model name' field of each core in /proc/cpuinfo it was noticed that there is a whitespace difference between the cores' model names.

After some quick investigation it was noticed that the model name fields were actually different -- processor 0's model name field had trailing whitespace removed, while the other processors did not.

Another way of seeing this behaviour is to convert spaces into underscores in the output of /proc/cpuinfo,

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

which shows the discrepancy.

This occurs because the kernel calls strim() on cpu 0's x86_model_id field to output a pretty message to the console in print_cpu_info(), and as a result strips the whitespace at the end of the ->x86_model_id field.

But, the ->x86_model_id field should be the same for the all identical CPUs in the box. Thus, we need to remove both leading and trailing whitespace.

As a result, the print_cpu_info() output looks like

smpboot: CPU0: AMD Opteron(TM) Processor 6272 (fam: 15, model: 01, stepping: 02)

and the x86_model_id field is correct on all processors on AMD platforms:

_____64_model_name :_AMD_Opteron(TM)_Processor_6272

Output is still correct on an Intel box:

____144_model_name :_Intel(R)_Xeon(R)_CPU_E7-8890_v3_@_2.50GHz

---
 arch/x86/kernel/cpu/common.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/common.c +4 -13
index a62cf04..41a8e9c 100644
@@ -419,7 +419,6 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
-	char *p, *q;
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	c->x86_model_id[48] = 0;
 
 	/*
-	 * Intel chips right-justify this string for some dumb reason;
-	 * undo that brain damage:
+	 * Remove leading whitespace on Intel processors and trailing
+	 * whitespace on AMD processors.
 	 */
-	p = q = &c->x86_model_id[0];
-	while (*p == ' ')
-		p++;
-	if (p != q) {
-		while (*p)
-			*q++ = *p++;
-		while (q <= &c->x86_model_id[48])
-			*q++ = '\0';	/* Zero-pad the rest */
-	}
+	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
@@ -1122,7 +1113,7 @@ void print_cpu_info(struct cpuinfo_x86 *c)
 		printk(KERN_CONT "%s ", vendor);
 
 	if (c->x86_model_id[0])
-		printk(KERN_CONT "%s", strim(c->x86_model_id));
+		printk(KERN_CONT "%s", c->x86_model_id);
 	else
 		printk(KERN_CONT "%d86", c->x86);
 
#469 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Quoted 1 line · tip-bot for Prarit Bhargava

x86/cpu: Strip any /proc/cpuinfo model name field whitespace

[]

Quoted 10 lines
arch/x86/kernel/cpu/common.c +2 -2
@@ -431,18 +430,10 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	c->x86_model_id[48] = 0;
 
 	/*
-	 * Intel chips right-justify this string for some dumb reason;
-	 * undo that brain damage:
+	 * Remove leading whitespace on Intel processors and trailing
+	 * whitespace on AMD processors.
 	 */

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c) · line 436

Quoted 10 lines
arch/x86/kernel/cpu/common.c +1 -9
-	p = q = &c->x86_model_id[0];
-	while (*p == ' ')
-		p++;
-	if (p != q) {
-		while (*p)
-			*q++ = *p++;
-		while (q <= &c->x86_model_id[48])
-			*q++ = '\0';	/* Zero-pad the rest */
-	}
+	memmove(c->x86_model_id, strim(c->x86_model_id), 48);

This code can memmove from beyond the x86_model_id field.

If the id was a single right justified char, to avoid overrunning the field, it'd be safer moving only the actual string and terminating 0 though this code is sub-optimal:

	memmove(c->x86_model_id, strim(c->x86_model_id),
		strlen(strim(c->x86_model_id) + 1);

Maybe:

	char *model = strim(c->x86_model_id);
	memmove(c->x86_model_id, model, strlen(model) + 1);
maintainer
#470 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Quoted 1 line · Joe Perches

This code can memmove from beyond the x86_model_id field.

... in the theoretical case where some model ID has more than 64 - 48 preceding white spaces.

I guess we want to be prepared here for insane CPU model IDs coming from virtualization.

Quoted 3 lines

Maybe:

	char *model = strim(c->x86_model_id);
	memmove(c->x86_model_id, model, strlen(model) + 1);

Yes, and additionally limit that string length:

---

arch/x86/kernel/cpu/common.c +7 -2
index b35c777df6df..9d1fd48486d6 100644
@@ -383,6 +383,9 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	const char *model;
+
+#define MODEL_ID_MAXLEN 48
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -391,13 +394,15 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-	c->x86_model_id[48] = 0;
+	c->x86_model_id[MODEL_ID_MAXLEN] = 0;
 
 	/*
 	 * Remove leading whitespace on Intel processors and trailing
 	 * whitespace on AMD processors.
 	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	model = strim(c->x86_model_id);
+
+	memmove(c->x86_model_id, model, strnlen(model, MODEL_ID_MAXLEN) + 1);
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#471 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

arch/x86/kernel/cpu/common.c

Quoted 17 lines · Borislav Petkov
Quoted 1 line · Joe Perches

This code can memmove from beyond the x86_model_id field.

... in the theoretical case where some model ID has more than 64 - 48 preceding white spaces.

I guess we want to be prepared here for insane CPU model IDs coming from virtualization.

Quoted 3 lines

Maybe:

	char *model = strim(c->x86_model_id);
	memmove(c->x86_model_id, model, strlen(model) + 1);

Yes, and additionally limit that string length:

---

arch/x86/kernel/cpu/common.c +0 -0

[]

Quoted 15 lines
arch/x86/kernel/cpu/common.c +3 -1
@@ -383,6 +383,9 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	const char *model;
+
+#define MODEL_ID_MAXLEN 48
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -391,13 +394,15 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-	c->x86_model_id[48] = 0;

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c) · line 405

Quoted 10 lines
arch/x86/kernel/cpu/common.c +4 -1
+	c->x86_model_id[MODEL_ID_MAXLEN] = 0;
 
 	/*
 	 * Remove leading whitespace on Intel processors and trailing
 	 * whitespace on AMD processors.
 	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	model = strim(c->x86_model_id);
+
+	memmove(c->x86_model_id, model, strnlen(model, MODEL_ID_MAXLEN) + 1);

I don't see any value in the #define or strnlen over strlen as it's guaranteed terminated by the = 0 above, but <shrug> thanks.

cheers, Joe

#472 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Quoted 36 lines · Joe Perches

arch/x86/kernel/cpu/common.c

Quoted 17 lines · Borislav Petkov
Quoted 1 line · Joe Perches

This code can memmove from beyond the x86_model_id field.

... in the theoretical case where some model ID has more than 64 - 48 preceding white spaces.

I guess we want to be prepared here for insane CPU model IDs coming from virtualization.

Quoted 3 lines

Maybe:

	char *model = strim(c->x86_model_id);
	memmove(c->x86_model_id, model, strlen(model) + 1);

Yes, and additionally limit that string length:

---

arch/x86/kernel/cpu/common.c +0 -0

[]

Quoted 17 lines
arch/x86/kernel/cpu/common.c +4 -1
@@ -383,6 +383,9 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	const char *model;
+
+#define MODEL_ID_MAXLEN 48
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -391,13 +394,15 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-	c->x86_model_id[48] = 0;
+	c->x86_model_id[MODEL_ID_MAXLEN] = 0;
 
Quoted 12 lines

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c) · line 405

Quoted 8 lines
arch/x86/kernel/cpu/common.c +3 -1
 	/*
 	 * Remove leading whitespace on Intel processors and trailing
 	 * whitespace on AMD processors.
 	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	model = strim(c->x86_model_id);
+
+	memmove(c->x86_model_id, model, strnlen(model, MODEL_ID_MAXLEN) + 1);

I don't see any value in the #define or strnlen over strlen as it's guaranteed terminated by the = 0 above, but <shrug> thanks.

FWIW, I agree with Joe here and don't think the #define is necessary. I will post a follow-up patch against tip on LKML shortly.

P.

Quoted 4 lines

cheers, Joe

maintainer
#473 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Quoted 2 lines · Prarit Bhargava

FWIW, I agree with Joe here and don't think the #define is necessary. I will post a follow-up patch against tip on LKML shortly.

No need, I have a better one:

---
From: Borislav Petkov <[email protected]>
Date: Tue, 26 May 2015 10:28:17 +0200
Subject: [PATCH] x86/cpu: Trim model id whitespace

We did try trimming whitespace surrounding the 'model name' field in /proc/cpuinfo since reportedly some userspace uses it in string comparisons and there were discrepancies:

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

However, there were issues with overlapping buffers, string sizes and non-byte-sized copies in the previous proposed solutions; see Link tags below for the whole farce.

So, instead of diddling with this more, let's simply extend what was there originally with trimming any present trailing whitespace. Final result is really simple and obvious.

Testing with the most insane model IDs qemu can generate, looks good:

.model_id = " My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = "My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " My funny model ID CPU",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " ",
______4_model_name :__

.model_id = "",
______4_model_name :_15/02

Cc Andy Lutomirski <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/kernel/cpu/common.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/common.c +17 -5
index 41a8e9cb30bc..351197cbbc8e 100644
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -419,6 +420,7 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	char *p, *q, *s;
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -429,11 +431,21 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
 
-	/*
-	 * Remove leading whitespace on Intel processors and trailing
-	 * whitespace on AMD processors.
-	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	/* Trim whitespace */
+	p = q = s = &c->x86_model_id[0];
+
+	while (*p == ' ')
+		p++;
+
+	while (*p) {
+		/* Note the last non-whitespace index */
+		if (!isspace(*p))
+			s = q;
+
+		*q++ = *p++;
+	}
+
+	*(s + 1) = '\0';
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
Signature · 8 lines
2.3.5

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
maintainer
#474 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Review

Quoted 6 lines · Borislav Petkov
(quoted diff) +6 -0
+	while (*p) {
+		/* Note the last non-whitespace index */
+		if (!isspace(*p))
+			s = q;
+
+		*q++ = *p++;

This should be optimized to not copy if there's no preceding whitespace and p == q:

From: Borislav Petkov <[email protected]>
Date: Tue, 26 May 2015 10:28:17 +0200
Subject: [PATCH] x86/cpu: Trim model id whitespace

We did try trimming whitespace surrounding the 'model name' field in /proc/cpuinfo since reportedly some userspace uses it in string comparisons and there were discrepancies:

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

However, there were issues with overlapping buffers, string sizes and non-byte-sized copies in the previous proposed solutions; see Link tags below for the whole farce.

So, instead of diddling with this more, let's simply extend what was there originally with trimming any present trailing whitespace. Final result is really simple and obvious.

Testing with the most insane model IDs qemu can generate, looks good:

.model_id = " My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = "My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " My funny model ID CPU",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " ",
______4_model_name :__

.model_id = "",
______4_model_name :_15/02

Cc Andy Lutomirski <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Fenghua Yu <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Igor Mammedov <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/kernel/cpu/common.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/common.c +22 -5
index 41a8e9cb30bc..18120a33a2c1 100644
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -419,6 +420,7 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	char *p, *q, *s;
 
 	if (c->extended_cpuid_level < 0x80000004)
 		return;
@@ -429,11 +431,26 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
 
-	/*
-	 * Remove leading whitespace on Intel processors and trailing
-	 * whitespace on AMD processors.
-	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	/* Trim whitespace */
+	p = q = s = &c->x86_model_id[0];
+
+	while (*p == ' ')
+		p++;
+
+	while (*p) {
+		/* Note the last non-whitespace index: */
+		if (!isspace(*p))
+			s = q;
+
+		/* Only copy if p advanced due to whitespace: */
+		if (p != q)
+			*q = *p;
+
+		p++;
+		q++;
+	}
+
+	*(s + 1) = '\0';
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
Signature · 8 lines
2.3.5

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#475 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Why?!

We are taking about 48 bytes run once per cpu. It isn't worth it to optimize, in fact the extra code size hurts more.

Quoted 123 lines · Borislav Petkov

arch/x86/kernel/cpu/common.c static void get_model_name(struct cpuinfo_x86 *c)

Quoted 6 lines · Borislav Petkov
arch/x86/kernel/cpu/common.c +6 -0
+	while (*p) {
+		/* Note the last non-whitespace index */
+		if (!isspace(*p))
+			s = q;
+
+		*q++ = *p++;

This should be optimized to not copy if there's no preceding whitespace and p == q:

From: Borislav Petkov <[email protected]>
Date: Tue, 26 May 2015 10:28:17 +0200
Subject: [PATCH] x86/cpu: Trim model id whitespace

We did try trimming whitespace surrounding the 'model name' field in /proc/cpuinfo since reportedly some userspace uses it in string comparisons and there were discrepancies:

[thetango@prarit ~]# grep "^model name" /proc/cpuinfo | uniq -c | sed 's/\ /_/g'
______1_model_name :_AMD_Opteron(TM)_Processor_6272
_____63_model_name :_AMD_Opteron(TM)_Processor_6272_________________

However, there were issues with overlapping buffers, string sizes and non-byte-sized copies in the previous proposed solutions; see Link tags below for the whole farce.

So, instead of diddling with this more, let's simply extend what was there originally with trimming any present trailing whitespace. Final result is really simple and obvious.

Testing with the most insane model IDs qemu can generate, looks good:

.model_id = " My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = "My funny model ID CPU ",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " My funny model ID CPU",
______4_model_name :_My_funny_model_ID_CPU

.model_id = " ",
______4_model_name :__

.model_id = "",
______4_model_name :_15/02

Cc: Andy Lutomirski <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Denys Vlasenko <[email protected]>
Cc: Fenghua Yu <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Igor Mammedov <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]> Link:
http://lkml.kernel.org/r/[email protected]
Link:
http://lkml.kernel.org/r/[email protected]

---
arch/x86/kernel/cpu/common.c | 27 ++++++++++++++++++++++-----

1 file changed, 22 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/common.c +2 -0
index 41a8e9cb30bc..18120a33a2c1 100644
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -419,6 +420,7 @@ static const struct cpu_dev
 *cpu_devs[X86_VENDOR_NUM] = {};
 static void get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
+	char *p, *q, *s;
 
 	if (c->extended_cpuid_level < 0x80000004)
		return;
arch/x86/kernel/cpu/common.c +20 -5
@@ -429,11 +431,26 @@ static void get_model_name(struct cpuinfo_x86 *c)
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
 
-	/*
-	 * Remove leading whitespace on Intel processors and trailing
-	 * whitespace on AMD processors.
-	 */
-	memmove(c->x86_model_id, strim(c->x86_model_id), 48);
+	/* Trim whitespace */
+	p = q = s = &c->x86_model_id[0];
+
+	while (*p == ' ')
+		p++;
+
+	while (*p) {
+		/* Note the last non-whitespace index: */
+		if (!isspace(*p))
+			s = q;
+
+		/* Only copy if p advanced due to whitespace: */
+		if (p != q)
+			*q = *p;
+
+		p++;
+		q++;
+	}
+
+	*(s + 1) = '\0';
 }
 
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
Signature · 1 line
Sent from my mobile phone.  Please pardon brevity and lack of formatting.
maintainer
#476 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Quoted 4 lines · H. Peter Anvin

Why?!

We are taking about 48 bytes run once per cpu. It isn't worth it to optimize, in fact the extra code size hurts more.

I wanted to save us the redundant copying of the exact same bytes. Because when there's no preceding whitespace, p and q point at the same thing so we end up doing *p = *p.

OTOH, without the optimization, the code is even simpler.

I can remove it if you wanna - I don't care all that much.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#477 lore raw

Re: [tip:x86/cpu] x86/cpu: Strip any /proc/ cpuinfo model name field whitespace

Quoted 6 lines · Borislav Petkov
Quoted 4 lines · H. Peter Anvin

Why?!

We are taking about 48 bytes run once per cpu. It isn't worth it to optimize, in fact the extra code size hurts more.

Quoted 8 lines

I wanted to save us the redundant copying of the exact same bytes. Because when there's no preceding whitespace, p and q point at the same thing so we end up doing *p = *p.

OTOH, without the optimization, the code is even simpler.

I can remove it if you wanna - I don't care all that much.

Yes, please. Actually, with a test inside the loop the way you have it, the resulting code will almost certainly be slower -- a redundant write to an already dirty cache line is way cheaper than a branch.

-hpa

maintainer
#478 lore raw

PATCH 15/18 x86/documentation: Move kernel-stacks doc one level up

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

... to Documentation/x86/ as it is going to collect more and not only 64-bit specific info.

Cc Ingo Molnar <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Michal Marek <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc X86 ML <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Andrew Morton <[email protected]>
---
 Documentation/x86/{x86_64 => }/kernel-stacks | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename Documentation/x86/{x86_64 => }/kernel-stacks (100%)
Documentation/x86/kernel-stacks renamed from Documentation/x86/x86_64/kernel-stacks +0 -0
similarity index 100%
rename from Documentation/x86/x86_64/kernel-stacks
rename to Documentation/x86/kernel-stacks
Signature · 1 line
1.9.0.258.g00eda23
#479 lore raw

[tip:x86/debug] x86/Documentation: Move kernel-stacks doc one level up

x86/Documentation: Move kernel-stacks doc one level up
Commit-ID:  54fd15780526c47fa29a85b066cf69996be59a59
Gitweb:     http://git.kernel.org/tip/54fd15780526c47fa29a85b066cf69996be59a59
Author:     Borislav Petkov <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:18 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:39:44 +0200

x86/Documentation: Move kernel-stacks doc one level up

... to Documentation/x86/ as it is going to collect more and not only 64-bit specific info.

Cc Andrew Morton <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Michal Marek <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 Documentation/x86/{x86_64 => }/kernel-stacks | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
Documentation/x86/kernel-stacks renamed from Documentation/x86/x86_64/kernel-stacks +0 -0
similarity index 100%
rename from Documentation/x86/x86_64/kernel-stacks
rename to Documentation/x86/kernel-stacks
maintainer
#480 lore raw

PATCH 16/18 x86/documentation: Remove STACKFAULT_STACK bulletpoint

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

Update the documentation after

6f442be2fb22 ("x86_64, traps: Stop using IST for #SS").

Cc Ingo Molnar <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Michal Marek <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc X86 ML <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Andrew Morton <[email protected]>
---
 Documentation/x86/kernel-stacks | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
Documentation/x86/kernel-stacks +3 -7
index e3c8a49d1a2f..c3c935b9d56e 100644
@@ -1,3 +1,6 @@
+Kernel stacks on x86-64 bit
+---------------------------
+
 Most of the text from Keith Owens, hacked by AK
 
 x86_64 page size (PAGE_SIZE) is 4K.
@@ -56,13 +59,6 @@ If that assumption is ever broken then the stacks will become corrupt.
 
 The currently assigned IST stacks are :-
 
-* STACKFAULT_STACK.  EXCEPTION_STKSZ (PAGE_SIZE).
-
-  Used for interrupt 12 - Stack Fault Exception (#SS).
-
-  This allows the CPU to recover from invalid stack segments. Rarely
-  happens.
-
 * DOUBLEFAULT_STACK.  EXCEPTION_STKSZ (PAGE_SIZE).
 
   Used for interrupt 8 - Double Fault Exception (#DF).
Signature · 1 line
1.9.0.258.g00eda23
#481 lore raw

[tip:x86/debug] x86/Documentation: Remove STACKFAULT_STACK bulletpoint

x86/Documentation: Remove STACKFAULT_STACK bulletpoint
Commit-ID:  d724a9a52b0026ac6a05440c079c9a618acfd8cf
Gitweb:     http://git.kernel.org/tip/d724a9a52b0026ac6a05440c079c9a618acfd8cf
Author:     Borislav Petkov <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:19 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:39:46 +0200

x86/Documentation: Remove STACKFAULT_STACK bulletpoint

Update the documentation after

6f442be2fb22 ("x86_64, traps: Stop using IST for #SS").

Cc Andrew Morton <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Michal Marek <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 Documentation/x86/kernel-stacks | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
Documentation/x86/kernel-stacks +3 -7
index e3c8a49..c3c935b 100644
@@ -1,3 +1,6 @@
+Kernel stacks on x86-64 bit
+---------------------------
+
 Most of the text from Keith Owens, hacked by AK
 
 x86_64 page size (PAGE_SIZE) is 4K.
@@ -56,13 +59,6 @@ If that assumption is ever broken then the stacks will become corrupt.
 
 The currently assigned IST stacks are :-
 
-* STACKFAULT_STACK.  EXCEPTION_STKSZ (PAGE_SIZE).
-
-  Used for interrupt 12 - Stack Fault Exception (#SS).
-
-  This allows the CPU to recover from invalid stack segments. Rarely
-  happens.
-
 * DOUBLEFAULT_STACK.  EXCEPTION_STKSZ (PAGE_SIZE).
 
   Used for interrupt 8 - Double Fault Exception (#DF).
maintainer
#482 lore raw

PATCH 17/18 x86/documentation: Adapt Ingo's explanation on printing backtraces

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

Hold it down for future reference, as the question about the question mark in stack traces keeps popping up.

Cc Ingo Molnar <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Michal Marek <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc X86 ML <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Brian Gerst <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Andrew Morton <[email protected]>
---
 Documentation/x86/kernel-stacks | 44 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
Documentation/x86/kernel-stacks +44 -0
index c3c935b9d56e..0f3a6c201943 100644
@@ -95,3 +95,47 @@ The currently assigned IST stacks are :-
   assumptions about the previous state of the kernel stack.
 
 For more details see the Intel IA32 or AMD AMD64 architecture manuals.
+
+
+Printing backtraces on x86
+--------------------------
+
+The question about the '?' preceding function names in an x86 stacktrace
+keeps popping up, here's an indepth explanation. It helps if the reader
+stares at print_context_stack() and the whole machinery in and around
+arch/x86/kernel/dumpstack.c.
+
+Adapted from Ingo's mail, Message-ID: <[email protected]>:
+
+We always scan the full kernel stack for return addresses stored on
+the kernel stack(s) [*], from stack top to stack bottom, and print out
+anything that 'looks like' a kernel text address.
+
+If it fits into the frame pointer chain, we print it without a question
+mark, knowing that it's part of the real backtrace.
+
+If the address does not fit into our expected frame pointer chain we
+still print it, but we print a '?'. It can mean two things:
+
+ - either the address is not part of the call chain: it's just stale
+   values on the kernel stack, from earlier function calls. This is
+   the common case.
+
+ - or it is part of the call chain, but the frame pointer was not set
+   up properly within the function, so we don't recognize it.
+
+This way we will always print out the real call chain (plus a few more
+entries), regardless of whether the frame pointer was set up correctly
+or not - but in most cases we'll get the call chain right as well. The
+entries printed are strictly in stack order, so you can deduce more
+information from that as well.
+
+The most important property of this method is that we _never_ lose
+information: we always strive to print _all_ addresses on the stack(s)
+that look like kernel text addresses, so if debug information is wrong,
+we still print out the real call chain as well - just with more question
+marks than ideal.
+
+[*] For things like IRQ and IST stacks, we also scan those stacks, in
+    the right order, and try to cross from one stack into another
+    reconstructing the call chain. This works most of the time.
Signature · 1 line
1.9.0.258.g00eda23
maintainer
#483 lore raw

PATCH 18/18 x86/mce: Fix monarch timeout setting through the mce= cmdline option

In reply to Borislav Petkov

From: Xie XiuQi <[email protected]>

Using "mce=1,10000000" on the kernel cmdline to change the monarch timeout does not work. The cause is that get_option() does parse a subsequent comma in the option string and signals that with a return value. So we don't need to check for a second comma ourselves.

---
 arch/x86/kernel/cpu/mcheck/mce.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +1 -4
index e535533d5ab8..e6580b9255de 100644
@@ -2008,11 +2008,8 @@ static int __init mcheck_enable(char *str)
 	else if (!strcmp(str, "bios_cmci_threshold"))
 		cfg->bios_cmci_threshold = true;
 	else if (isdigit(str[0])) {
-		get_option(&str, &(cfg->tolerant));
-		if (*str == ',') {
-			++str;
+		if (get_option(&str, &(cfg->tolerant)) == 2)
 			get_option(&str, &(cfg->monarch_timeout));
-		}
 	} else {
 		pr_info("mce argument %s ignored. Please use /sys\n", str);
 		return 0;
Signature · 1 line
1.9.0.258.g00eda23
#484 lore raw

[tip:x86/core] x86/mce: Fix monarch timeout setting through the mce= cmdline option

x86/mce: Fix monarch timeout setting through the mce= cmdline option
Commit-ID:  5c31b2800d8d3e735e5ecac8fc13d1cf862fd330
Gitweb:     http://git.kernel.org/tip/5c31b2800d8d3e735e5ecac8fc13d1cf862fd330
Author:     Xie XiuQi <[email protected]>
AuthorDate: Tue, 26 May 2015 10:28:21 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 May 2015 14:39:14 +0200

x86/mce: Fix monarch timeout setting through the mce= cmdline option

Using "mce=1,10000000" on the kernel cmdline to change the monarch timeout does not work. The cause is that get_option() does parse a subsequent comma in the option string and signals that with a return value. So we don't need to check for a second comma ourselves.

---
 arch/x86/kernel/cpu/mcheck/mce.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +1 -4
index 521e501..0cbcd31 100644
@@ -2014,11 +2014,8 @@ static int __init mcheck_enable(char *str)
 	else if (!strcmp(str, "bios_cmci_threshold"))
 		cfg->bios_cmci_threshold = true;
 	else if (isdigit(str[0])) {
-		get_option(&str, &(cfg->tolerant));
-		if (*str == ',') {
-			++str;
+		if (get_option(&str, &cfg->tolerant) == 2)
 			get_option(&str, &(cfg->monarch_timeout));
-		}
 	} else {
 		pr_info("mce argument %s ignored. Please use /sys\n", str);
 		return 0;