|
@@ -53,7 +53,7 @@
|
|
*/
|
|
*/
|
|
#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
|
|
#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
|
|
|
|
|
|
-int swiotlb_force;
|
|
|
|
|
|
+enum swiotlb_force swiotlb_force;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Used to do a quick range check in swiotlb_tbl_unmap_single and
|
|
* Used to do a quick range check in swiotlb_tbl_unmap_single and
|
|
@@ -82,6 +82,12 @@ static phys_addr_t io_tlb_overflow_buffer;
|
|
static unsigned int *io_tlb_list;
|
|
static unsigned int *io_tlb_list;
|
|
static unsigned int io_tlb_index;
|
|
static unsigned int io_tlb_index;
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Max segment that we can provide which (if pages are contingous) will
|
|
|
|
+ * not be bounced (unless SWIOTLB_FORCE is set).
|
|
|
|
+ */
|
|
|
|
+unsigned int max_segment;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* We need to save away the original address corresponding to a mapped entry
|
|
* We need to save away the original address corresponding to a mapped entry
|
|
* for the sync operations.
|
|
* for the sync operations.
|
|
@@ -106,8 +112,12 @@ setup_io_tlb_npages(char *str)
|
|
}
|
|
}
|
|
if (*str == ',')
|
|
if (*str == ',')
|
|
++str;
|
|
++str;
|
|
- if (!strcmp(str, "force"))
|
|
|
|
- swiotlb_force = 1;
|
|
|
|
|
|
+ if (!strcmp(str, "force")) {
|
|
|
|
+ swiotlb_force = SWIOTLB_FORCE;
|
|
|
|
+ } else if (!strcmp(str, "noforce")) {
|
|
|
|
+ swiotlb_force = SWIOTLB_NO_FORCE;
|
|
|
|
+ io_tlb_nslabs = 1;
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -120,6 +130,20 @@ unsigned long swiotlb_nr_tbl(void)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
|
|
EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
|
|
|
|
|
|
|
|
+unsigned int swiotlb_max_segment(void)
|
|
|
|
+{
|
|
|
|
+ return max_segment;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(swiotlb_max_segment);
|
|
|
|
+
|
|
|
|
+void swiotlb_set_max_segment(unsigned int val)
|
|
|
|
+{
|
|
|
|
+ if (swiotlb_force == SWIOTLB_FORCE)
|
|
|
|
+ max_segment = 1;
|
|
|
|
+ else
|
|
|
|
+ max_segment = rounddown(val, PAGE_SIZE);
|
|
|
|
+}
|
|
|
|
+
|
|
/* default to 64MB */
|
|
/* default to 64MB */
|
|
#define IO_TLB_DEFAULT_SIZE (64UL<<20)
|
|
#define IO_TLB_DEFAULT_SIZE (64UL<<20)
|
|
unsigned long swiotlb_size_or_default(void)
|
|
unsigned long swiotlb_size_or_default(void)
|
|
@@ -201,6 +225,7 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
|
|
if (verbose)
|
|
if (verbose)
|
|
swiotlb_print_info();
|
|
swiotlb_print_info();
|
|
|
|
|
|
|
|
+ swiotlb_set_max_segment(io_tlb_nslabs << IO_TLB_SHIFT);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -279,6 +304,7 @@ swiotlb_late_init_with_default_size(size_t default_size)
|
|
rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs);
|
|
rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs);
|
|
if (rc)
|
|
if (rc)
|
|
free_pages((unsigned long)vstart, order);
|
|
free_pages((unsigned long)vstart, order);
|
|
|
|
+
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -333,6 +359,8 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
|
|
|
|
|
|
late_alloc = 1;
|
|
late_alloc = 1;
|
|
|
|
|
|
|
|
+ swiotlb_set_max_segment(io_tlb_nslabs << IO_TLB_SHIFT);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
cleanup4:
|
|
cleanup4:
|
|
@@ -347,6 +375,7 @@ cleanup2:
|
|
io_tlb_end = 0;
|
|
io_tlb_end = 0;
|
|
io_tlb_start = 0;
|
|
io_tlb_start = 0;
|
|
io_tlb_nslabs = 0;
|
|
io_tlb_nslabs = 0;
|
|
|
|
+ max_segment = 0;
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -375,6 +404,7 @@ void __init swiotlb_free(void)
|
|
PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
|
|
PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
|
|
}
|
|
}
|
|
io_tlb_nslabs = 0;
|
|
io_tlb_nslabs = 0;
|
|
|
|
+ max_segment = 0;
|
|
}
|
|
}
|
|
|
|
|
|
int is_swiotlb_buffer(phys_addr_t paddr)
|
|
int is_swiotlb_buffer(phys_addr_t paddr)
|
|
@@ -543,8 +573,15 @@ static phys_addr_t
|
|
map_single(struct device *hwdev, phys_addr_t phys, size_t size,
|
|
map_single(struct device *hwdev, phys_addr_t phys, size_t size,
|
|
enum dma_data_direction dir, unsigned long attrs)
|
|
enum dma_data_direction dir, unsigned long attrs)
|
|
{
|
|
{
|
|
- dma_addr_t start_dma_addr = phys_to_dma(hwdev, io_tlb_start);
|
|
|
|
|
|
+ dma_addr_t start_dma_addr;
|
|
|
|
|
|
|
|
+ if (swiotlb_force == SWIOTLB_NO_FORCE) {
|
|
|
|
+ dev_warn_ratelimited(hwdev, "Cannot do DMA to address %pa\n",
|
|
|
|
+ &phys);
|
|
|
|
+ return SWIOTLB_MAP_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ start_dma_addr = phys_to_dma(hwdev, io_tlb_start);
|
|
return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size,
|
|
return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size,
|
|
dir, attrs);
|
|
dir, attrs);
|
|
}
|
|
}
|
|
@@ -721,6 +758,9 @@ static void
|
|
swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
|
|
swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
|
|
int do_panic)
|
|
int do_panic)
|
|
{
|
|
{
|
|
|
|
+ if (swiotlb_force == SWIOTLB_NO_FORCE)
|
|
|
|
+ return;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Ran out of IOMMU space for this operation. This is very bad.
|
|
* Ran out of IOMMU space for this operation. This is very bad.
|
|
* Unfortunately the drivers cannot handle this operation properly.
|
|
* Unfortunately the drivers cannot handle this operation properly.
|
|
@@ -763,7 +803,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
|
|
* we can safely return the device addr and not worry about bounce
|
|
* we can safely return the device addr and not worry about bounce
|
|
* buffering it.
|
|
* buffering it.
|
|
*/
|
|
*/
|
|
- if (dma_capable(dev, dev_addr, size) && !swiotlb_force)
|
|
|
|
|
|
+ if (dma_capable(dev, dev_addr, size) && swiotlb_force != SWIOTLB_FORCE)
|
|
return dev_addr;
|
|
return dev_addr;
|
|
|
|
|
|
trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force);
|
|
trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force);
|
|
@@ -904,7 +944,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
|
|
phys_addr_t paddr = sg_phys(sg);
|
|
phys_addr_t paddr = sg_phys(sg);
|
|
dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
|
|
dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
|
|
|
|
|
|
- if (swiotlb_force ||
|
|
|
|
|
|
+ if (swiotlb_force == SWIOTLB_FORCE ||
|
|
!dma_capable(hwdev, dev_addr, sg->length)) {
|
|
!dma_capable(hwdev, dev_addr, sg->length)) {
|
|
phys_addr_t map = map_single(hwdev, sg_phys(sg),
|
|
phys_addr_t map = map_single(hwdev, sg_phys(sg),
|
|
sg->length, dir, attrs);
|
|
sg->length, dir, attrs);
|