Adding kmap_atomic_prot_pfn (was: [git pull] drm patches for2.6.27-rc1)

From: Keith Packard
Date: Thu Oct 23 2008 - 16:22:55 EST

We just ran some numbers on a box with PAT enabled and broken MTRRs.
Finally we have a test platform for the difference between kmap_atomic
and kmap_atomic_prot. Using regular kmap_atomic on this platform, we get
UC access to the graphics device; sending data from the CPU is a bit
slow. Adding kmap_atomic_prot_pfn and specifying WC access raises that
by a fairly significant factor, taking our CPU utilization for
copy_from_user from 40% to 2%.

Here's a patch which adds kmap_atomic_prot_pfn to the kernel for this
usage. When we add native io-mapping support instead of sitting on top
of kmap, we can remove this function.

I've reworked the io_mapping patches to use this function as well, along
with cleaning up the i915 code along the lines of Linus' current
version. I'll post those if this patch looks acceptable.

From e3f633dcb36889fa85ea06cca339072df3c44ae0 Mon Sep 17 00:00:00 2001
From: Keith Packard <keithp@xxxxxxxxxx>
Date: Thu, 23 Oct 2008 11:53:45 -0700
Subject: [PATCH] Add kmap_atomic_prot_pfn

kmap_atomic_prot_pfn is a mixture of kmap_atomic_prot and kmap_atomic_pfn,
accepting both a pfn instead of a page and an explicit protection value.

Signed-off-by: Keith Packard <keithp@xxxxxxxxxx>
arch/x86/mm/highmem_32.c | 19 +++++++++++++++++++
include/asm-x86/highmem.h | 1 +
include/linux/highmem.h | 1 +
3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index bcc079c..91ae5e8 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -139,6 +139,25 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */

+/* This is the same as kmap_atomic_prot() but can map memory that doesn't
+ * have a struct page associated with it.
+ */
+void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+ enum fixed_addresses idx;
+ unsigned long vaddr;
+ pagefault_disable();
+ idx = type + KM_TYPE_NR*smp_processor_id();
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ set_pte(kmap_pte-idx, pfn_pte(pfn, prot));
+ arch_flush_lazy_mmu_mode();
+ return (void*) vaddr;
+EXPORT_SYMBOL_GPL(kmap_atomic_prot_pfn); /* temporarily in use by i915 GEM until vmap */
struct page *kmap_atomic_to_page(void *ptr)
unsigned long idx, vaddr = (unsigned long)ptr;
diff --git a/include/asm-x86/highmem.h b/include/asm-x86/highmem.h
index bc3f6a2..a1f8f8c 100644
--- a/include/asm-x86/highmem.h
+++ b/include/asm-x86/highmem.h
@@ -66,6 +66,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *kvaddr, enum km_type type);
void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
+void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
struct page *kmap_atomic_to_page(void *ptr);

diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 7dcbc82..7fbee2c 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -55,6 +55,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx)

#define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0)
#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
+#define kmap_atomic_prot_pfn(pfn, idx, prot) kmap_atomic_prot(pfn_to_page(pfn), (idx), (prot))
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)

#define kmap_flush_unused() do {} while(0)


Attachment: signature.asc
Description: This is a digitally signed message part