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 CC: Loic Prylli CC: Brice Goglin --- 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)