Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen: Make clear that swiotlb and biomerge are dealing with DMA address

The swiotlb is required when programming a DMA address on ARM when a
device is not protected by an IOMMU.

In this case, the DMA address should always be equal to the machine address.
For DOM0 memory, Xen ensure it by have an identity mapping between the
guest address and host address. However, when mapping a foreign grant
reference, the 1:1 model doesn't work.

For ARM guest, most of the callers of pfn_to_mfn expects to get a GFN
(Guest Frame Number), i.e a PFN (Page Frame Number) from the Linux point
of view given that all ARM guest are auto-translated.

Even though the name pfn_to_mfn is misleading, we need to ensure that
those caller get a GFN and not by mistake a MFN. In pratical, I haven't
seen error related to this but we should fix it for the sake of
correctness.

In order to fix the implementation of pfn_to_mfn on ARM in a follow-up
patch, we have to introduce new helpers to return the DMA from a PFN and
the invert.

On x86, the new helpers will be an alias of pfn_to_mfn and mfn_to_pfn.

The helpers will be used in swiotlb and xen_biovec_phys_mergeable.

This is necessary in the latter because we have to ensure that the
biovec code will not try to merge a biovec using foreign page and
another using Linux memory.

Lastly, the helper mfn_to_local_pfn has been renamed to bfn_to_local_pfn
given that the only usage was in swiotlb.

Signed-off-by: Julien Grall <julien.grall@citrix.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>

+40 -17
+21 -2
arch/arm/include/asm/xen/page.h
··· 52 52 return mfn; 53 53 } 54 54 55 - #define mfn_to_local_pfn(mfn) mfn_to_pfn(mfn) 55 + /* Pseudo-physical <-> BUS conversion */ 56 + static inline unsigned long pfn_to_bfn(unsigned long pfn) 57 + { 58 + unsigned long mfn; 59 + 60 + if (phys_to_mach.rb_node != NULL) { 61 + mfn = __pfn_to_mfn(pfn); 62 + if (mfn != INVALID_P2M_ENTRY) 63 + return mfn; 64 + } 65 + 66 + return pfn; 67 + } 68 + 69 + static inline unsigned long bfn_to_pfn(unsigned long bfn) 70 + { 71 + return bfn; 72 + } 73 + 74 + #define bfn_to_local_pfn(bfn) bfn_to_pfn(bfn) 56 75 57 76 /* VIRT <-> MACHINE conversion */ 58 77 #define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v))) ··· 115 96 116 97 bool xen_arch_need_swiotlb(struct device *dev, 117 98 unsigned long pfn, 118 - unsigned long mfn); 99 + unsigned long bfn); 119 100 unsigned long xen_get_swiotlb_free_pages(unsigned int order); 120 101 121 102 #endif /* _ASM_ARM_XEN_PAGE_H */
+2 -2
arch/arm/xen/mm.c
··· 139 139 140 140 bool xen_arch_need_swiotlb(struct device *dev, 141 141 unsigned long pfn, 142 - unsigned long mfn) 142 + unsigned long bfn) 143 143 { 144 - return (!hypercall_cflush && (pfn != mfn) && !is_device_dma_coherent(dev)); 144 + return (!hypercall_cflush && (pfn != bfn) && !is_device_dma_coherent(dev)); 145 145 } 146 146 147 147 int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
+6 -2
arch/x86/include/asm/xen/page.h
··· 176 176 return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset); 177 177 } 178 178 179 + /* Pseudo-physical <-> Bus conversion */ 180 + #define pfn_to_bfn(pfn) pfn_to_mfn(pfn) 181 + #define bfn_to_pfn(bfn) mfn_to_pfn(bfn) 182 + 179 183 /* 180 184 * We detect special mappings in one of two ways: 181 185 * 1. If the MFN is an I/O page then Xen will set the m2p entry ··· 200 196 * require. In all the cases we care about, the FOREIGN_FRAME bit is 201 197 * masked (e.g., pfn_to_mfn()) so behaviour there is correct. 202 198 */ 203 - static inline unsigned long mfn_to_local_pfn(unsigned long mfn) 199 + static inline unsigned long bfn_to_local_pfn(unsigned long mfn) 204 200 { 205 201 unsigned long pfn; 206 202 ··· 266 262 267 263 static inline bool xen_arch_need_swiotlb(struct device *dev, 268 264 unsigned long pfn, 269 - unsigned long mfn) 265 + unsigned long bfn) 270 266 { 271 267 return false; 272 268 }
+3 -3
drivers/xen/biomerge.c
··· 6 6 bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, 7 7 const struct bio_vec *vec2) 8 8 { 9 - unsigned long mfn1 = pfn_to_mfn(page_to_pfn(vec1->bv_page)); 10 - unsigned long mfn2 = pfn_to_mfn(page_to_pfn(vec2->bv_page)); 9 + unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page)); 10 + unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page)); 11 11 12 12 return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) && 13 - ((mfn1 == mfn2) || ((mfn1+1) == mfn2)); 13 + ((bfn1 == bfn2) || ((bfn1+1) == bfn2)); 14 14 } 15 15 EXPORT_SYMBOL(xen_biovec_phys_mergeable);
+8 -8
drivers/xen/swiotlb-xen.c
··· 82 82 */ 83 83 static inline dma_addr_t xen_phys_to_bus(phys_addr_t paddr) 84 84 { 85 - unsigned long mfn = pfn_to_mfn(PFN_DOWN(paddr)); 86 - dma_addr_t dma = (dma_addr_t)mfn << PAGE_SHIFT; 85 + unsigned long bfn = pfn_to_bfn(PFN_DOWN(paddr)); 86 + dma_addr_t dma = (dma_addr_t)bfn << PAGE_SHIFT; 87 87 88 88 dma |= paddr & ~PAGE_MASK; 89 89 ··· 92 92 93 93 static inline phys_addr_t xen_bus_to_phys(dma_addr_t baddr) 94 94 { 95 - unsigned long pfn = mfn_to_pfn(PFN_DOWN(baddr)); 95 + unsigned long pfn = bfn_to_pfn(PFN_DOWN(baddr)); 96 96 dma_addr_t dma = (dma_addr_t)pfn << PAGE_SHIFT; 97 97 phys_addr_t paddr = dma; 98 98 ··· 110 110 unsigned int offset, 111 111 size_t length) 112 112 { 113 - unsigned long next_mfn; 113 + unsigned long next_bfn; 114 114 int i; 115 115 int nr_pages; 116 116 117 - next_mfn = pfn_to_mfn(pfn); 117 + next_bfn = pfn_to_bfn(pfn); 118 118 nr_pages = (offset + length + PAGE_SIZE-1) >> PAGE_SHIFT; 119 119 120 120 for (i = 1; i < nr_pages; i++) { 121 - if (pfn_to_mfn(++pfn) != ++next_mfn) 121 + if (pfn_to_bfn(++pfn) != ++next_bfn) 122 122 return 0; 123 123 } 124 124 return 1; ··· 138 138 139 139 static int is_xen_swiotlb_buffer(dma_addr_t dma_addr) 140 140 { 141 - unsigned long mfn = PFN_DOWN(dma_addr); 142 - unsigned long pfn = mfn_to_local_pfn(mfn); 141 + unsigned long bfn = PFN_DOWN(dma_addr); 142 + unsigned long pfn = bfn_to_local_pfn(bfn); 143 143 phys_addr_t paddr; 144 144 145 145 /* If the address is outside our domain, it CAN