Skip to content

Commit 6810df8

Browse files
committed
xen-swiotlb: When doing coherent alloc/dealloc check before swizzling the MFNs.
The process to swizzle a Machine Frame Number (MFN) is not always necessary. Especially if we know that we actually do not have to do it. In this patch we check the MFN against the device's coherent DMA mask and if the requested page(s) are contingous. If it all checks out we will just return the bus addr without doing the memory swizzle. Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>
1 parent 12e13ac commit 6810df8

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

drivers/xen/swiotlb-xen.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
209209
int order = get_order(size);
210210
u64 dma_mask = DMA_BIT_MASK(32);
211211
unsigned long vstart;
212+
phys_addr_t phys;
213+
dma_addr_t dev_addr;
212214

213215
/*
214216
* Ignore region specifiers - the kernel's ideas of
@@ -224,18 +226,26 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
224226
vstart = __get_free_pages(flags, order);
225227
ret = (void *)vstart;
226228

229+
if (!ret)
230+
return ret;
231+
227232
if (hwdev && hwdev->coherent_dma_mask)
228-
dma_mask = dma_alloc_coherent_mask(hwdev, flags);
233+
dma_mask = hwdev->coherent_dma_mask;
229234

230-
if (ret) {
235+
phys = virt_to_phys(ret);
236+
dev_addr = xen_phys_to_bus(phys);
237+
if (((dev_addr + size - 1 <= dma_mask)) &&
238+
!range_straddles_page_boundary(phys, size))
239+
*dma_handle = dev_addr;
240+
else {
231241
if (xen_create_contiguous_region(vstart, order,
232242
fls64(dma_mask)) != 0) {
233243
free_pages(vstart, order);
234244
return NULL;
235245
}
236-
memset(ret, 0, size);
237246
*dma_handle = virt_to_machine(ret).maddr;
238247
}
248+
memset(ret, 0, size);
239249
return ret;
240250
}
241251
EXPORT_SYMBOL_GPL(xen_swiotlb_alloc_coherent);
@@ -245,11 +255,21 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
245255
dma_addr_t dev_addr)
246256
{
247257
int order = get_order(size);
258+
phys_addr_t phys;
259+
u64 dma_mask = DMA_BIT_MASK(32);
248260

249261
if (dma_release_from_coherent(hwdev, order, vaddr))
250262
return;
251263

252-
xen_destroy_contiguous_region((unsigned long)vaddr, order);
264+
if (hwdev && hwdev->coherent_dma_mask)
265+
dma_mask = hwdev->coherent_dma_mask;
266+
267+
phys = virt_to_phys(vaddr);
268+
269+
if (((dev_addr + size - 1 > dma_mask)) ||
270+
range_straddles_page_boundary(phys, size))
271+
xen_destroy_contiguous_region((unsigned long)vaddr, order);
272+
253273
free_pages((unsigned long)vaddr, order);
254274
}
255275
EXPORT_SYMBOL_GPL(xen_swiotlb_free_coherent);

0 commit comments

Comments
 (0)