--- arch/x86_64/mm/ioremap.c | 45 ++++++++++++++++++++++++++++++++++++--------- include/asm-x86_64/io.h | 3 ++- 2 files changed, 38 insertions(+), 10 deletions(-) Index: linux/arch/x86_64/mm/ioremap.c =================================================================== --- linux.orig/arch/x86_64/mm/ioremap.c +++ linux/arch/x86_64/mm/ioremap.c @@ -214,14 +214,17 @@ void __iomem * __ioremap(unsigned long p remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); return NULL; } - if (flags) { - if (reserve_mattr(phys_addr, phys_addr + size, flags, NULL) < 0) - goto out; - if (ioremap_change_attr(phys_addr, size, flags) < 0) { - free_mattr(phys_addr, phys_addr + size, flags); - goto out; - } - } + + /* For plain ioremap() get the existing attributes. Otherwise + check against the existing ones */ + if (reserve_mattr(phys_addr, phys_addr + size, flags, + flags ? NULL : &flags) < 0) + goto out; + + if (flags && ioremap_change_attr(phys_addr, size, flags) < 0) { + free_mattr(phys_addr, phys_addr + size, flags); + goto out; + } return (__force void __iomem *) (offset + (char *)addr); out: @@ -232,7 +235,7 @@ out: EXPORT_SYMBOL(__ioremap); /** - * ioremap_nocache - map bus memory into CPU space + * ioremap_nocache - map bus memory into CPU space uncached * @offset: bus address of the memory * @size: size of the resource to map * @@ -260,6 +263,30 @@ void __iomem *ioremap_nocache (unsigned EXPORT_SYMBOL(ioremap_nocache); /** + * ioremap_wc - map bus memory into CPU space write combined + * @offset: bus address of the memory + * @size: size of the resource to map + * + * ioremap_wc performs a platform specific sequence of operations to + * make bus memory CPU accessible via the readb/readw/readl/writeb/ + * writew/writel functions and the other mmio helpers. The returned + * address is not guaranteed to be usable directly as a virtual + * address. + * + * This version of ioremap ensures that the memory is marked write combining. + * Write combining allows faster writes to some hardware devices. + * See also iounmap_nocache for more details. + * + * Must be freed with iounmap. + */ +void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size) +{ + return __ioremap(phys_addr, size, _PAGE_WC); +} +EXPORT_SYMBOL(ioremap_wc); + + +/** * iounmap - Free a IO remapping * @addr: virtual address from ioremap_* * Index: linux/include/asm-x86_64/io.h =================================================================== --- linux.orig/include/asm-x86_64/io.h +++ linux/include/asm-x86_64/io.h @@ -142,7 +142,8 @@ extern void early_iounmap(void *addr, un * it's useful if some control registers are in such an area and write combining * or read caching is not desirable: */ -extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); +extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size); +extern void __iomem * ioremap_wc(unsigned long offset, unsigned long size); extern void iounmap(volatile void __iomem *addr); /*