>From 7cd44581d15aaa3b2ef38a4d76ba19dd50e7cb7b Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 14 Oct 2009 19:25:33 +0200 Subject: [PATCH 1/4] Add new mtrr_add_unaligned function This function creates multiple MTRR entries for unaligned memory regions. Signed-off-by: Thomas Schlichter --- arch/x86/include/asm/mtrr.h | 6 ++++++ arch/x86/kernel/cpu/mtrr/main.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 4365ffd..9f447c4 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -116,6 +116,8 @@ extern int mtrr_add(unsigned long base, unsigned long size, unsigned int type, bool increment); extern int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, bool increment); +extern void mtrr_add_unaligned(unsigned long base, unsigned long size, + unsigned int type, int *mtrr_usage); extern int mtrr_del(int reg, unsigned long base, unsigned long size); extern int mtrr_del_page(int reg, unsigned long base, unsigned long size); extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); @@ -146,6 +148,10 @@ static inline int mtrr_add_page(unsigned long base, unsigned long size, { return -ENODEV; } +static inline void mtrr_add_unaligned(unsigned long base, unsigned long size, + unsigned int type, int *mtrr_usage) +{ +} static inline int mtrr_del(int reg, unsigned long base, unsigned long size) { return -ENODEV; diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 84e83de..5654ef7 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -487,6 +487,36 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, } EXPORT_SYMBOL(mtrr_add); +void mtrr_add_unaligned(unsigned long base, unsigned long size, + unsigned int type, int *mtrr_usage) +{ + int i; + unsigned long ptr1, ptr2, end = base + size; + + // round down size to next power ot two + size = __rounddown_pow_of_two(size); + + // accordingly align pointers + ptr1 = ptr2 = (base + size - 1) & ~(size - 1); + + while (size >= PAGE_SIZE) { + if (ptr1 + size <= end) { + i = mtrr_add(ptr1, size, type, !!mtrr_usage); + if (i >= 0 && mtrr_usage) + ++mtrr_usage[i]; + ptr1 += size; + } + if (base + size <= ptr2) { + ptr2 -= size; + i = mtrr_add(ptr2, size, type, !!mtrr_usage); + if (i >= 0 && mtrr_usage) + ++mtrr_usage[i]; + } + size >>= 1; + } +} +EXPORT_SYMBOL(mtrr_add_unaligned); + /** * mtrr_del_page - delete a memory type region * @reg: Register returned by mtrr_add -- 1.6.5.1