This patch fixes - marking I-cache clean of pages DMAed to now only done for IA64 - broken multiple inclusion in include/asm-x86_64/swiotlb.h - missing phys-to-virt translation in swiotlb_sync_sg() - missing call to mark_clean in swiotlb_sync_sg() Signed-off-by: Jan Beulich Index: sle10-sp1-2006-12-18/arch/ia64/mm/init.c =================================================================== --- sle10-sp1-2006-12-18.orig/arch/ia64/mm/init.c 2006-03-20 06:53:29.000000000 +0100 +++ sle10-sp1-2006-12-18/arch/ia64/mm/init.c 2006-12-20 12:02:01.000000000 +0100 @@ -123,6 +123,25 @@ lazy_mmu_prot_update (pte_t pte) set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } +/* + * Since DMA is i-cache coherent, any (complete) pages that were written via + * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to + * flush them when they get mapped into an executable vm-area. + */ +void +dma_mark_clean(void *addr, size_t size) +{ + unsigned long pg_addr, end; + + pg_addr = PAGE_ALIGN((unsigned long) addr); + end = (unsigned long) addr + size; + while (pg_addr + PAGE_SIZE <= end) { + struct page *page = virt_to_page(pg_addr); + set_bit(PG_arch_1, &page->flags); + pg_addr += PAGE_SIZE; + } +} + inline void ia64_set_rbs_bot (void) { Index: sle10-sp1-2006-12-18/include/asm-ia64/dma.h =================================================================== --- sle10-sp1-2006-12-18.orig/include/asm-ia64/dma.h 2006-03-20 06:53:29.000000000 +0100 +++ sle10-sp1-2006-12-18/include/asm-ia64/dma.h 2006-12-20 12:02:01.000000000 +0100 @@ -20,4 +20,6 @@ extern unsigned long MAX_DMA_ADDRESS; #define free_dma(x) +void dma_mark_clean(void *addr, size_t size); + #endif /* _ASM_IA64_DMA_H */ Index: sle10-sp1-2006-12-18/include/asm-x86_64/mach-xen/asm/dma-mapping.h =================================================================== --- sle10-sp1-2006-12-18.orig/include/asm-x86_64/mach-xen/asm/dma-mapping.h 2006-12-20 15:53:41.000000000 +0100 +++ sle10-sp1-2006-12-18/include/asm-x86_64/mach-xen/asm/dma-mapping.h 2006-12-20 12:02:01.000000000 +0100 @@ -10,7 +10,6 @@ #include #include -#include struct dma_mapping_ops { int (*mapping_error)(dma_addr_t dma_addr); Index: sle10-sp1-2006-12-18/include/asm-x86_64/swiotlb.h =================================================================== --- sle10-sp1-2006-12-18.orig/include/asm-x86_64/swiotlb.h 2006-12-20 15:53:41.000000000 +0100 +++ sle10-sp1-2006-12-18/include/asm-x86_64/swiotlb.h 2006-12-20 15:53:57.000000000 +0100 @@ -1,5 +1,5 @@ #ifndef _ASM_SWIOTLB_H -#define _ASM_SWTIOLB_H 1 +#define _ASM_SWIOTLB_H 1 #include @@ -59,4 +59,6 @@ extern int swiotlb; extern void pci_swiotlb_init(void); -#endif /* _ASM_SWTIOLB_H */ +static inline void dma_mark_clean(void *addr, size_t size) {} + +#endif /* _ASM_SWIOTLB_H */ Index: sle10-sp1-2006-12-18/lib/swiotlb.c =================================================================== --- sle10-sp1-2006-12-18.orig/lib/swiotlb.c 2006-03-20 06:53:29.000000000 +0100 +++ sle10-sp1-2006-12-18/lib/swiotlb.c 2006-12-20 12:02:01.000000000 +0100 @@ -560,25 +560,6 @@ swiotlb_map_single(struct device *hwdev, } /* - * Since DMA is i-cache coherent, any (complete) pages that were written via - * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to - * flush them when they get mapped into an executable vm-area. - */ -static void -mark_clean(void *addr, size_t size) -{ - unsigned long pg_addr, end; - - pg_addr = PAGE_ALIGN((unsigned long) addr); - end = (unsigned long) addr + size; - while (pg_addr + PAGE_SIZE <= end) { - struct page *page = virt_to_page(pg_addr); - set_bit(PG_arch_1, &page->flags); - pg_addr += PAGE_SIZE; - } -} - -/* * Unmap a single streaming mode DMA translation. The dma_addr and size must * match what was provided for in a previous swiotlb_map_single call. All * other usages are undefined. @@ -597,7 +578,7 @@ swiotlb_unmap_single(struct device *hwde if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) unmap_single(hwdev, dma_addr, size, dir); else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + dma_mark_clean(dma_addr, size); } /* @@ -621,7 +602,7 @@ swiotlb_sync_single(struct device *hwdev if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) sync_single(hwdev, dma_addr, size, dir, target); else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + dma_mark_clean(dma_addr, size); } void @@ -653,7 +634,7 @@ swiotlb_sync_single_range(struct device if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) sync_single(hwdev, dma_addr, size, dir, target); else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + dma_mark_clean(dma_addr, size); } void @@ -704,7 +685,6 @@ swiotlb_map_sg(struct device *hwdev, str dev_addr = virt_to_phys(addr); if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) { void *map = map_single(hwdev, addr, sg->length, dir); - sg->dma_address = virt_to_bus(map); if (!map) { /* Don't panic here, we expect map_sg users to do proper error handling. */ @@ -713,6 +693,7 @@ swiotlb_map_sg(struct device *hwdev, str sg[0].dma_length = 0; return 0; } + sg->dma_address = virt_to_bus(map); } else sg->dma_address = dev_addr; sg->dma_length = sg->length; @@ -737,7 +718,7 @@ swiotlb_unmap_sg(struct device *hwdev, s if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir); else if (dir == DMA_FROM_DEVICE) - mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); + dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } /* @@ -758,8 +739,10 @@ swiotlb_sync_sg(struct device *hwdev, st for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - sync_single(hwdev, (void *) sg->dma_address, + sync_single(hwdev, phys_to_virt(sg->dma_address), sg->dma_length, dir, target); + else if (dir == DMA_FROM_DEVICE) + dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } void