diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/io.h | 7 | ||||
-rw-r--r-- | arch/x86/include/asm/mtrr.h | 10 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/main.c | 71 |
3 files changed, 87 insertions, 1 deletions
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index d8e8eefbe24c..34f69cb9350a 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h | |||
@@ -345,4 +345,11 @@ extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, | |||
345 | 345 | ||
346 | #define IO_SPACE_LIMIT 0xffff | 346 | #define IO_SPACE_LIMIT 0xffff |
347 | 347 | ||
348 | #ifdef CONFIG_MTRR | ||
349 | extern int __must_check arch_phys_wc_add(unsigned long base, | ||
350 | unsigned long size); | ||
351 | extern void arch_phys_wc_del(int handle); | ||
352 | #define arch_phys_wc_add arch_phys_wc_add | ||
353 | #endif | ||
354 | |||
348 | #endif /* _ASM_X86_IO_H */ | 355 | #endif /* _ASM_X86_IO_H */ |
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index e235582f9930..f768f6298419 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h | |||
@@ -26,7 +26,10 @@ | |||
26 | #include <uapi/asm/mtrr.h> | 26 | #include <uapi/asm/mtrr.h> |
27 | 27 | ||
28 | 28 | ||
29 | /* The following functions are for use by other drivers */ | 29 | /* |
30 | * The following functions are for use by other drivers that cannot use | ||
31 | * arch_phys_wc_add and arch_phys_wc_del. | ||
32 | */ | ||
30 | # ifdef CONFIG_MTRR | 33 | # ifdef CONFIG_MTRR |
31 | extern u8 mtrr_type_lookup(u64 addr, u64 end); | 34 | extern u8 mtrr_type_lookup(u64 addr, u64 end); |
32 | extern void mtrr_save_fixed_ranges(void *); | 35 | extern void mtrr_save_fixed_ranges(void *); |
@@ -45,6 +48,7 @@ extern void mtrr_aps_init(void); | |||
45 | extern void mtrr_bp_restore(void); | 48 | extern void mtrr_bp_restore(void); |
46 | extern int mtrr_trim_uncached_memory(unsigned long end_pfn); | 49 | extern int mtrr_trim_uncached_memory(unsigned long end_pfn); |
47 | extern int amd_special_default_mtrr(void); | 50 | extern int amd_special_default_mtrr(void); |
51 | extern int phys_wc_to_mtrr_index(int handle); | ||
48 | # else | 52 | # else |
49 | static inline u8 mtrr_type_lookup(u64 addr, u64 end) | 53 | static inline u8 mtrr_type_lookup(u64 addr, u64 end) |
50 | { | 54 | { |
@@ -80,6 +84,10 @@ static inline int mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
80 | static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) | 84 | static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) |
81 | { | 85 | { |
82 | } | 86 | } |
87 | static inline int phys_wc_to_mtrr_index(int handle) | ||
88 | { | ||
89 | return -1; | ||
90 | } | ||
83 | 91 | ||
84 | #define mtrr_ap_init() do {} while (0) | 92 | #define mtrr_ap_init() do {} while (0) |
85 | #define mtrr_bp_init() do {} while (0) | 93 | #define mtrr_bp_init() do {} while (0) |
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 726bf963c227..3533d4d16f8c 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c | |||
@@ -51,9 +51,13 @@ | |||
51 | #include <asm/e820.h> | 51 | #include <asm/e820.h> |
52 | #include <asm/mtrr.h> | 52 | #include <asm/mtrr.h> |
53 | #include <asm/msr.h> | 53 | #include <asm/msr.h> |
54 | #include <asm/pat.h> | ||
54 | 55 | ||
55 | #include "mtrr.h" | 56 | #include "mtrr.h" |
56 | 57 | ||
58 | /* arch_phys_wc_add returns an MTRR register index plus this offset. */ | ||
59 | #define MTRR_TO_PHYS_WC_OFFSET 1000 | ||
60 | |||
57 | u32 num_var_ranges; | 61 | u32 num_var_ranges; |
58 | 62 | ||
59 | unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES]; | 63 | unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES]; |
@@ -524,6 +528,73 @@ int mtrr_del(int reg, unsigned long base, unsigned long size) | |||
524 | } | 528 | } |
525 | EXPORT_SYMBOL(mtrr_del); | 529 | EXPORT_SYMBOL(mtrr_del); |
526 | 530 | ||
531 | /** | ||
532 | * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable | ||
533 | * @base: Physical base address | ||
534 | * @size: Size of region | ||
535 | * | ||
536 | * If PAT is available, this does nothing. If PAT is unavailable, it | ||
537 | * attempts to add a WC MTRR covering size bytes starting at base and | ||
538 | * logs an error if this fails. | ||
539 | * | ||
540 | * Drivers must store the return value to pass to mtrr_del_wc_if_needed, | ||
541 | * but drivers should not try to interpret that return value. | ||
542 | */ | ||
543 | int arch_phys_wc_add(unsigned long base, unsigned long size) | ||
544 | { | ||
545 | int ret; | ||
546 | |||
547 | if (pat_enabled) | ||
548 | return 0; /* Success! (We don't need to do anything.) */ | ||
549 | |||
550 | ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true); | ||
551 | if (ret < 0) { | ||
552 | pr_warn("Failed to add WC MTRR for [%p-%p]; performance may suffer.", | ||
553 | (void *)base, (void *)(base + size - 1)); | ||
554 | return ret; | ||
555 | } | ||
556 | return ret + MTRR_TO_PHYS_WC_OFFSET; | ||
557 | } | ||
558 | EXPORT_SYMBOL(arch_phys_wc_add); | ||
559 | |||
560 | /* | ||
561 | * arch_phys_wc_del - undoes arch_phys_wc_add | ||
562 | * @handle: Return value from arch_phys_wc_add | ||
563 | * | ||
564 | * This cleans up after mtrr_add_wc_if_needed. | ||
565 | * | ||
566 | * The API guarantees that mtrr_del_wc_if_needed(error code) and | ||
567 | * mtrr_del_wc_if_needed(0) do nothing. | ||
568 | */ | ||
569 | void arch_phys_wc_del(int handle) | ||
570 | { | ||
571 | if (handle >= 1) { | ||
572 | WARN_ON(handle < MTRR_TO_PHYS_WC_OFFSET); | ||
573 | mtrr_del(handle - MTRR_TO_PHYS_WC_OFFSET, 0, 0); | ||
574 | } | ||
575 | } | ||
576 | EXPORT_SYMBOL(arch_phys_wc_del); | ||
577 | |||
578 | /* | ||
579 | * phys_wc_to_mtrr_index - translates arch_phys_wc_add's return value | ||
580 | * @handle: Return value from arch_phys_wc_add | ||
581 | * | ||
582 | * This will turn the return value from arch_phys_wc_add into an mtrr | ||
583 | * index suitable for debugging. | ||
584 | * | ||
585 | * Note: There is no legitimate use for this function, except possibly | ||
586 | * in printk line. Alas there is an illegitimate use in some ancient | ||
587 | * drm ioctls. | ||
588 | */ | ||
589 | int phys_wc_to_mtrr_index(int handle) | ||
590 | { | ||
591 | if (handle < MTRR_TO_PHYS_WC_OFFSET) | ||
592 | return -1; | ||
593 | else | ||
594 | return handle - MTRR_TO_PHYS_WC_OFFSET; | ||
595 | } | ||
596 | EXPORT_SYMBOL_GPL(phys_wc_to_mtrr_index); | ||
597 | |||
527 | /* | 598 | /* |
528 | * HACK ALERT! | 599 | * HACK ALERT! |
529 | * These should be called implicitly, but we can't yet until all the initcall | 600 | * These should be called implicitly, but we can't yet until all the initcall |