diff options
author | Geert Uytterhoeven <geert+renesas@glider.be> | 2016-12-16 08:28:42 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-01-26 02:24:44 -0500 |
commit | 41c6b3e8989e79772a50429d92cf91959bcce96d (patch) | |
tree | e1098b8fb35ab3f524703d89c01d885c6ed76d54 | |
parent | 1fd1e6cd63143cf5d198a536d875dfc88ce179bc (diff) |
swiotlb: Add swiotlb=noforce debug option
commit fff5d99225107f5f13fe4a9805adc2a1c4b5fb00 upstream.
On architectures like arm64, swiotlb is tied intimately to the core
architecture DMA support. In addition, ZONE_DMA cannot be disabled.
To aid debugging and catch devices not supporting DMA to memory outside
the 32-bit address space, add a kernel command line option
"swiotlb=noforce", which disables the use of bounce buffers.
If specified, trying to map memory that cannot be used with DMA will
fail, and a rate-limited warning will be printed.
Note that io_tlb_nslabs is set to 1, which is the minimal supported
value.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | Documentation/kernel-parameters.txt | 3 | ||||
-rw-r--r-- | include/linux/swiotlb.h | 1 | ||||
-rw-r--r-- | include/trace/events/swiotlb.h | 3 | ||||
-rw-r--r-- | lib/swiotlb.c | 18 |
4 files changed, 21 insertions, 4 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 37babf91f2cb..922dec8fa07e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -3998,10 +3998,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
3998 | it if 0 is given (See Documentation/cgroup-v1/memory.txt) | 3998 | it if 0 is given (See Documentation/cgroup-v1/memory.txt) |
3999 | 3999 | ||
4000 | swiotlb= [ARM,IA-64,PPC,MIPS,X86] | 4000 | swiotlb= [ARM,IA-64,PPC,MIPS,X86] |
4001 | Format: { <int> | force } | 4001 | Format: { <int> | force | noforce } |
4002 | <int> -- Number of I/O TLB slabs | 4002 | <int> -- Number of I/O TLB slabs |
4003 | force -- force using of bounce buffers even if they | 4003 | force -- force using of bounce buffers even if they |
4004 | wouldn't be automatically used by the kernel | 4004 | wouldn't be automatically used by the kernel |
4005 | noforce -- Never use bounce buffers (for debugging) | ||
4005 | 4006 | ||
4006 | switches= [HW,M68k] | 4007 | switches= [HW,M68k] |
4007 | 4008 | ||
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 746ecebbd4ca..d2613536fd03 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h | |||
@@ -12,6 +12,7 @@ struct scatterlist; | |||
12 | enum swiotlb_force { | 12 | enum swiotlb_force { |
13 | SWIOTLB_NORMAL, /* Default - depending on HW DMA mask etc. */ | 13 | SWIOTLB_NORMAL, /* Default - depending on HW DMA mask etc. */ |
14 | SWIOTLB_FORCE, /* swiotlb=force */ | 14 | SWIOTLB_FORCE, /* swiotlb=force */ |
15 | SWIOTLB_NO_FORCE, /* swiotlb=noforce */ | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | extern enum swiotlb_force swiotlb_force; | 18 | extern enum swiotlb_force swiotlb_force; |
diff --git a/include/trace/events/swiotlb.h b/include/trace/events/swiotlb.h index 5e2e30a7efce..288c0c54a2b4 100644 --- a/include/trace/events/swiotlb.h +++ b/include/trace/events/swiotlb.h | |||
@@ -39,7 +39,8 @@ TRACE_EVENT(swiotlb_bounced, | |||
39 | __entry->size, | 39 | __entry->size, |
40 | __print_symbolic(__entry->swiotlb_force, | 40 | __print_symbolic(__entry->swiotlb_force, |
41 | { SWIOTLB_NORMAL, "NORMAL" }, | 41 | { SWIOTLB_NORMAL, "NORMAL" }, |
42 | { SWIOTLB_FORCE, "FORCE" })) | 42 | { SWIOTLB_FORCE, "FORCE" }, |
43 | { SWIOTLB_NO_FORCE, "NO_FORCE" })) | ||
43 | ); | 44 | ); |
44 | 45 | ||
45 | #endif /* _TRACE_SWIOTLB_H */ | 46 | #endif /* _TRACE_SWIOTLB_H */ |
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 68e8f49c7e06..ad1d2962d129 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
@@ -106,8 +106,12 @@ setup_io_tlb_npages(char *str) | |||
106 | } | 106 | } |
107 | if (*str == ',') | 107 | if (*str == ',') |
108 | ++str; | 108 | ++str; |
109 | if (!strcmp(str, "force")) | 109 | if (!strcmp(str, "force")) { |
110 | swiotlb_force = SWIOTLB_FORCE; | 110 | swiotlb_force = SWIOTLB_FORCE; |
111 | } else if (!strcmp(str, "noforce")) { | ||
112 | swiotlb_force = SWIOTLB_NO_FORCE; | ||
113 | io_tlb_nslabs = 1; | ||
114 | } | ||
111 | 115 | ||
112 | return 0; | 116 | return 0; |
113 | } | 117 | } |
@@ -541,8 +545,15 @@ static phys_addr_t | |||
541 | map_single(struct device *hwdev, phys_addr_t phys, size_t size, | 545 | map_single(struct device *hwdev, phys_addr_t phys, size_t size, |
542 | enum dma_data_direction dir) | 546 | enum dma_data_direction dir) |
543 | { | 547 | { |
544 | dma_addr_t start_dma_addr = phys_to_dma(hwdev, io_tlb_start); | 548 | dma_addr_t start_dma_addr; |
549 | |||
550 | if (swiotlb_force == SWIOTLB_NO_FORCE) { | ||
551 | dev_warn_ratelimited(hwdev, "Cannot do DMA to address %pa\n", | ||
552 | &phys); | ||
553 | return SWIOTLB_MAP_ERROR; | ||
554 | } | ||
545 | 555 | ||
556 | start_dma_addr = phys_to_dma(hwdev, io_tlb_start); | ||
546 | return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir); | 557 | return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir); |
547 | } | 558 | } |
548 | 559 | ||
@@ -707,6 +718,9 @@ static void | |||
707 | swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir, | 718 | swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir, |
708 | int do_panic) | 719 | int do_panic) |
709 | { | 720 | { |
721 | if (swiotlb_force == SWIOTLB_NO_FORCE) | ||
722 | return; | ||
723 | |||
710 | /* | 724 | /* |
711 | * Ran out of IOMMU space for this operation. This is very bad. | 725 | * Ran out of IOMMU space for this operation. This is very bad. |
712 | * Unfortunately the drivers cannot handle this operation properly. | 726 | * Unfortunately the drivers cannot handle this operation properly. |