in swiotlb-xen.c [155:218]
int xen_swiotlb_init(void)
{
enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN;
unsigned long bytes = swiotlb_size_or_default();
unsigned long nslabs = bytes >> IO_TLB_SHIFT;
unsigned int order, repeat = 3;
int rc = -ENOMEM;
char *start;
if (io_tlb_default_mem.nslabs) {
pr_warn("swiotlb buffer already initialized\n");
return -EEXIST;
}
retry:
m_ret = XEN_SWIOTLB_ENOMEM;
order = get_order(bytes);
/*
* Get IO TLB memory from any location.
*/
#define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
start = (void *)xen_get_swiotlb_free_pages(order);
if (start)
break;
order--;
}
if (!start)
goto exit;
if (order != get_order(bytes)) {
pr_warn("Warning: only able to allocate %ld MB for software IO TLB\n",
(PAGE_SIZE << order) >> 20);
nslabs = SLABS_PER_PAGE << order;
bytes = nslabs << IO_TLB_SHIFT;
}
/*
* And replace that memory with pages under 4GB.
*/
rc = xen_swiotlb_fixup(start, nslabs);
if (rc) {
free_pages((unsigned long)start, order);
m_ret = XEN_SWIOTLB_EFIXUP;
goto error;
}
rc = swiotlb_late_init_with_tbl(start, nslabs);
if (rc)
return rc;
swiotlb_set_max_segment(PAGE_SIZE);
return 0;
error:
if (nslabs > 1024 && repeat--) {
/* Min is 2MB */
nslabs = max(1024UL, ALIGN(nslabs >> 1, IO_TLB_SEGSIZE));
bytes = nslabs << IO_TLB_SHIFT;
pr_info("Lowering to %luMB\n", bytes >> 20);
goto retry;
}
exit:
pr_err("%s (rc:%d)\n", xen_swiotlb_error(m_ret), rc);
return rc;
}