[PATCH 2/2] PAT support for write combining in pci_mmap_page_range

From: Cédric Augonnet
Date: Mon Aug 06 2007 - 22:04:25 EST



Adds support for write-combining in pci_mmap_page_range using PAT6.

Some distinction has to be made between huge pages and normal pages since
the position of the bit encoding PAT depends on that.

Signed-off-by: Cedric Augonnet <cedric.augonnet@xxxxxxxxxxxx>
CC: Loic Prylli <loic@xxxxxxxx>
CC: Brice Goglin <brice@xxxxxxxx>
---
diff -urN 2.6.23-rc2/arch/i386/pci/i386.c 2.6.23-rc2-pat/arch/i386/pci/i386.c
--- 2.6.23-rc2/arch/i386/pci/i386.c 2007-07-31 10:48:58.000000000 -0400
+++ 2.6.23-rc2-pat/arch/i386/pci/i386.c 2007-08-06 18:19:18.000000000 -0400
@@ -299,13 +299,20 @@
* address on this platform.
*/
prot = pgprot_val(vma->vm_page_prot);
- if (boot_cpu_data.x86 > 3)
- prot |= _PAGE_PCD | _PAGE_PWT;
- vma->vm_page_prot = __pgprot(prot);

- /* Write-combine setting is ignored, it is changed via the mtrr
- * interfaces on this platform.
+ /* Unless PAT is enabling write combining, it is here ignored and
+ * changed via the mtrr interfaces on this platform.
*/
+ if (cpu_has_pat && write_combine) {
+ /* PAT bit is not the same if we have huge pages */
+ vma->vm_page_prot =
+ __pgprot_wc(prot, (vma->vm_flags & VM_HUGETLB));
+ } else {
+ if (boot_cpu_data.x86 > 3)
+ prot |= _PAGE_PCD | _PAGE_PWT;
+ vma->vm_page_prot = __pgprot(prot);
+ }
+
if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
diff -urN 2.6.23-rc2/include/asm-i386/pgtable.h 2.6.23-rc2-pat/include/asm-i386/pgtable.h
--- 2.6.23-rc2/include/asm-i386/pgtable.h 2007-08-06 15:17:12.000000000 -0400
+++ 2.6.23-rc2-pat/include/asm-i386/pgtable.h 2007-08-06 18:33:48.000000000 -0400
@@ -119,6 +119,12 @@
#define _PAGE_UNUSED2 0x400
#define _PAGE_UNUSED3 0x800

+/* defined for write combining support with PAT enabled */
+#define _PAGE_PAT6 0x088 /* PAT6 for 4K pages */
+#define _PAGE_PAT6_HUGE 0x1008 /* PAT6 for huge pages */
+#define _PAGE_WR_CMB _PAGE_PAT6
+#define _PAGE_WR_CMB_HUGE _PAGE_PAT6_HUGE
+
/* If _PAGE_PRESENT is clear, we use these: */
#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */
#define _PAGE_PROTNONE 0x080 /* if the user mapped it with PROT_NONE;
@@ -171,6 +177,11 @@
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)

+#define __pgprot_wc(flag, is_huge_page) \
+ (__pgprot((is_huge_page) ? \
+ ((flag) & (~_PAGE_PWT)) | _PAGE_WR_CMB_HUGE : \
+ ((flag) & (~_PAGE_PWT)) | _PAGE_WR_CMB) )
+
/*
* The i386 can't do page protection for execute, and considers that
* the same are read. Also, write permissions imply read permissions.
diff -urN 2.6.23-rc2/include/asm-x86_64/pgtable.h 2.6.23-rc2-pat/include/asm-x86_64/pgtable.h
--- 2.6.23-rc2/include/asm-x86_64/pgtable.h 2007-08-06 15:17:15.000000000 -0400
+++ 2.6.23-rc2-pat/include/asm-x86_64/pgtable.h 2007-08-06 18:29:28.000000000 -0400
@@ -164,6 +164,13 @@
#define _PAGE_GLOBAL 0x100 /* Global TLB entry */

#define _PAGE_PROTNONE 0x080 /* If not present */
+
+/* defined for write combining support with PAT enabled */
+#define _PAGE_PAT6 0x088 /* PAT6 for 4K pages */
+#define _PAGE_PAT6_HUGE 0x1008 /* PAT6 for huge pages */
+#define _PAGE_WR_CMB _PAGE_PAT6
+#define _PAGE_WR_CMB_HUGE _PAGE_PAT6_HUGE
+
#define _PAGE_NX (_AC(1,UL)<<_PAGE_BIT_NX)

#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -196,6 +203,11 @@
#define __PAGE_KERNEL_LARGE_EXEC \
(__PAGE_KERNEL_EXEC | _PAGE_PSE)

+#define __pgprot_wc(flag, is_huge_page) \
+ (__pgprot((is_huge_page) ? \
+ ((flag) & (~_PAGE_PWT)) | _PAGE_WR_CMB_HUGE : \
+ ((flag) & (~_PAGE_PWT)) | _PAGE_WR_CMB))
+
#define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)

#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)