aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/io.h7
-rw-r--r--arch/x86/include/asm/mtrr.h10
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c71
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
349extern int __must_check arch_phys_wc_add(unsigned long base,
350 unsigned long size);
351extern 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
31extern u8 mtrr_type_lookup(u64 addr, u64 end); 34extern u8 mtrr_type_lookup(u64 addr, u64 end);
32extern void mtrr_save_fixed_ranges(void *); 35extern void mtrr_save_fixed_ranges(void *);
@@ -45,6 +48,7 @@ extern void mtrr_aps_init(void);
45extern void mtrr_bp_restore(void); 48extern void mtrr_bp_restore(void);
46extern int mtrr_trim_uncached_memory(unsigned long end_pfn); 49extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
47extern int amd_special_default_mtrr(void); 50extern int amd_special_default_mtrr(void);
51extern int phys_wc_to_mtrr_index(int handle);
48# else 52# else
49static inline u8 mtrr_type_lookup(u64 addr, u64 end) 53static 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)
80static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) 84static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
81{ 85{
82} 86}
87static 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
57u32 num_var_ranges; 61u32 num_var_ranges;
58 62
59unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES]; 63unsigned 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}
525EXPORT_SYMBOL(mtrr_del); 529EXPORT_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 */
543int 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}
558EXPORT_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 */
569void 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}
576EXPORT_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 */
589int 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}
596EXPORT_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