aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/mtrr
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2013-05-13 19:58:40 -0400
committerDave Airlie <airlied@redhat.com>2013-05-30 23:02:52 -0400
commitd0d98eedee2178c803dd824bb09f52b0e2ac1811 (patch)
tree302ece15c574dc061b1dea4e67125c7b01342154 /arch/x86/kernel/cpu/mtrr
parente81f3d81e282a156b47c1c2c09a1976e34073060 (diff)
Add arch_phys_wc_{add, del} to manipulate WC MTRRs if needed
Several drivers currently use mtrr_add through various #ifdef guards and/or drm wrappers. The vast majority of them want to add WC MTRRs on x86 systems and don't actually need the MTRR if PAT (i.e. ioremap_wc, etc) are working. arch_phys_wc_add and arch_phys_wc_del are new functions, available on all architectures and configurations, that add WC MTRRs on x86 if needed (and handle errors) and do nothing at all otherwise. They're also easier to use than mtrr_add and mtrr_del, so the call sites can be simplified. As an added benefit, this will avoid wasting MTRRs and possibly warning pointlessly on PAT-supporting systems. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'arch/x86/kernel/cpu/mtrr')
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c71
1 files changed, 71 insertions, 0 deletions
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