drivers/xen/swiotlb-xen.c

Source file repositories/reference/linux-study-clean/drivers/xen/swiotlb-xen.c

File Facts

System
Linux kernel
Corpus path
drivers/xen/swiotlb-xen.c
Extension
.c
Size
12805 bytes
Lines
453
Domain
Driver Families
Bucket
drivers/xen
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

range_requires_alignment(phys, size)) {
		if (xen_create_contiguous_region(phys, order, fls64(dma_mask),
				dma_handle) != 0)
			goto out_free_pages;
		SetPageXenRemapped(virt_to_page(ret));
	}

	memset(ret, 0, size);
	return ret;

out_free_pages:
	free_pages((unsigned long)ret, get_order(size));
	return NULL;
}

static void
xen_swiotlb_free_coherent(struct device *dev, size_t size, void *vaddr,
		dma_addr_t dma_handle, unsigned long attrs)
{
	phys_addr_t phys = virt_to_phys(vaddr);
	int order = get_order(size);

	/* Convert the size to actually allocated. */
	size = ALIGN(size, XEN_PAGE_SIZE);

	if (WARN_ON_ONCE(dma_handle + size - 1 > dev->coherent_dma_mask) ||
	    WARN_ON_ONCE(range_straddles_page_boundary(phys, size) ||
			 range_requires_alignment(phys, size)))
	    	return;

	if (TestClearPageXenRemapped(virt_to_page(vaddr)))
		xen_destroy_contiguous_region(phys, order);
	free_pages((unsigned long)vaddr, get_order(size));
}
#endif /* CONFIG_X86 */

/*
 * Map a single buffer of the indicated size for DMA in streaming mode.  The
 * physical address to use is returned.
 *
 * Once the device is given the dma address, the device owns this memory until
 * either xen_swiotlb_unmap_phys or xen_swiotlb_dma_sync_single is performed.
 */
static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,
				size_t size, enum dma_data_direction dir,
				unsigned long attrs)
{
	dma_addr_t dev_addr;
	phys_addr_t map;

	BUG_ON(dir == DMA_NONE);

	if (attrs & DMA_ATTR_MMIO) {
		if (unlikely(!dma_capable(dev, phys, size, false))) {
			dev_err_once(
				dev,
				"DMA addr %pa+%zu overflow (mask %llx, bus limit %llx).\n",
				&phys, size, *dev->dma_mask,
				dev->bus_dma_limit);
			WARN_ON_ONCE(1);
			return DMA_MAPPING_ERROR;
		}
		return phys;
	}

	dev_addr = xen_phys_to_dma(dev, phys);

	/*
	 * If the address happens to be in the device's DMA window,
	 * we can safely return the device addr and not worry about bounce
	 * buffering it.
	 */
	if (dma_capable(dev, dev_addr, size, true) &&
	    !dma_kmalloc_needs_bounce(dev, size, dir) &&
	    !range_straddles_page_boundary(phys, size) &&
		!xen_arch_need_swiotlb(dev, phys, dev_addr) &&
		!is_swiotlb_force_bounce(dev))
		goto done;

	/*
	 * Oh well, have to allocate and map a bounce buffer.
	 */
	trace_swiotlb_bounced(dev, dev_addr, size);

	map = swiotlb_tbl_map_single(dev, phys, size, 0, dir, attrs);
	if (map == (phys_addr_t)DMA_MAPPING_ERROR)
		return DMA_MAPPING_ERROR;

	phys = map;
	dev_addr = xen_phys_to_dma(dev, map);

Annotation

Implementation Notes