>From 9ef568a835c5033efb8032f1a4415ac2a128d4fc Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 14 Oct 2009 19:25:33 +0200 Subject: [PATCH 1/6] 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 | 8 ++++++++ arch/x86/kernel/cpu/mtrr/main.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 4365ffd..2e0d99d 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -116,6 +116,9 @@ 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, bool increment, + 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 +149,11 @@ 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, bool increment, + 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..5bf769b 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, bool increment, 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, increment); + if (i >= 0 && increment && mtrr_usage) + ++mtrr_usage[i]; + ptr1 += size; + } + if (base + size <= ptr2) { + ptr2 -= size; + i = mtrr_add(ptr2, size, type, increment); + if (i >= 0 && increment && 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