]>
Commit | Line | Data |
---|---|---|
12ecb97d GKH |
1 | From 500fcc08a32bfd54f11951ba81530775df15c474 Mon Sep 17 00:00:00 2001 |
2 | From: Marek Szyprowski <m.szyprowski@samsung.com> | |
3 | Date: Mon, 3 Apr 2017 08:21:00 +0200 | |
4 | Subject: serial: samsung: Add missing checks for dma_map_single failure | |
5 | ||
6 | From: Marek Szyprowski <m.szyprowski@samsung.com> | |
7 | ||
8 | commit 500fcc08a32bfd54f11951ba81530775df15c474 upstream. | |
9 | ||
10 | This patch adds missing checks for dma_map_single() failure and proper error | |
11 | reporting. Although this issue was harmless on ARM architecture, it is always | |
12 | good to use the DMA mapping API in a proper way. This patch fixes the following | |
13 | DMA API debug warning: | |
14 | ||
15 | WARNING: CPU: 1 PID: 3785 at lib/dma-debug.c:1171 check_unmap+0x8a0/0xf28 | |
16 | dma-pl330 121a0000.pdma: DMA-API: device driver failed to check map error[device address=0x000000006e0f9000] [size=4096 bytes] [mapped as single] | |
17 | Modules linked in: | |
18 | CPU: 1 PID: 3785 Comm: (agetty) Tainted: G W 4.11.0-rc1-00137-g07ca963-dirty #59 | |
19 | Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) | |
20 | [<c011aaa4>] (unwind_backtrace) from [<c01127c0>] (show_stack+0x20/0x24) | |
21 | [<c01127c0>] (show_stack) from [<c06ba5d8>] (dump_stack+0x84/0xa0) | |
22 | [<c06ba5d8>] (dump_stack) from [<c0139528>] (__warn+0x14c/0x180) | |
23 | [<c0139528>] (__warn) from [<c01395a4>] (warn_slowpath_fmt+0x48/0x50) | |
24 | [<c01395a4>] (warn_slowpath_fmt) from [<c072a114>] (check_unmap+0x8a0/0xf28) | |
25 | [<c072a114>] (check_unmap) from [<c072a834>] (debug_dma_unmap_page+0x98/0xc8) | |
26 | [<c072a834>] (debug_dma_unmap_page) from [<c0803874>] (s3c24xx_serial_shutdown+0x314/0x52c) | |
27 | [<c0803874>] (s3c24xx_serial_shutdown) from [<c07f5124>] (uart_port_shutdown+0x54/0x88) | |
28 | [<c07f5124>] (uart_port_shutdown) from [<c07f522c>] (uart_shutdown+0xd4/0x110) | |
29 | [<c07f522c>] (uart_shutdown) from [<c07f6a8c>] (uart_hangup+0x9c/0x208) | |
30 | [<c07f6a8c>] (uart_hangup) from [<c07c426c>] (__tty_hangup+0x49c/0x634) | |
31 | [<c07c426c>] (__tty_hangup) from [<c07c78ac>] (tty_ioctl+0xc88/0x16e4) | |
32 | [<c07c78ac>] (tty_ioctl) from [<c03b5f2c>] (do_vfs_ioctl+0xc4/0xd10) | |
33 | [<c03b5f2c>] (do_vfs_ioctl) from [<c03b6bf4>] (SyS_ioctl+0x7c/0x8c) | |
34 | [<c03b6bf4>] (SyS_ioctl) from [<c010b4a0>] (ret_fast_syscall+0x0/0x3c) | |
35 | ||
36 | Reported-by: Seung-Woo Kim <sw0312.kim@samsung.com> | |
37 | Fixes: 62c37eedb74c8 ("serial: samsung: add dma reqest/release functions") | |
38 | Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> | |
39 | Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> | |
40 | Reviewed-by: Shuah Khan <shuahkh@osg.samsung.com> | |
41 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
42 | ||
43 | --- | |
b9c50d6c GKH |
44 | drivers/tty/serial/samsung.c | 30 ++++++++++++++++++++++++------ |
45 | 1 file changed, 24 insertions(+), 6 deletions(-) | |
12ecb97d GKH |
46 | |
47 | --- a/drivers/tty/serial/samsung.c | |
48 | +++ b/drivers/tty/serial/samsung.c | |
b9c50d6c | 49 | @@ -860,6 +860,7 @@ static int s3c24xx_serial_request_dma(st |
12ecb97d GKH |
50 | { |
51 | struct s3c24xx_uart_dma *dma = p->dma; | |
b9c50d6c | 52 | unsigned long flags; |
12ecb97d GKH |
53 | + int ret; |
54 | ||
55 | /* Default slave configuration parameters */ | |
56 | dma->rx_conf.direction = DMA_DEV_TO_MEM; | |
b9c50d6c | 57 | @@ -884,8 +885,8 @@ static int s3c24xx_serial_request_dma(st |
12ecb97d GKH |
58 | |
59 | dma->tx_chan = dma_request_chan(p->port.dev, "tx"); | |
60 | if (IS_ERR(dma->tx_chan)) { | |
61 | - dma_release_channel(dma->rx_chan); | |
62 | - return PTR_ERR(dma->tx_chan); | |
63 | + ret = PTR_ERR(dma->tx_chan); | |
64 | + goto err_release_rx; | |
65 | } | |
66 | ||
67 | dmaengine_slave_config(dma->tx_chan, &dma->tx_conf); | |
b9c50d6c | 68 | @@ -894,15 +895,17 @@ static int s3c24xx_serial_request_dma(st |
12ecb97d GKH |
69 | dma->rx_size = PAGE_SIZE; |
70 | ||
71 | dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL); | |
72 | - | |
73 | if (!dma->rx_buf) { | |
74 | - dma_release_channel(dma->rx_chan); | |
75 | - dma_release_channel(dma->tx_chan); | |
76 | - return -ENOMEM; | |
77 | + ret = -ENOMEM; | |
78 | + goto err_release_tx; | |
79 | } | |
80 | ||
81 | dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf, | |
82 | dma->rx_size, DMA_FROM_DEVICE); | |
83 | + if (dma_mapping_error(p->port.dev, dma->rx_addr)) { | |
84 | + ret = -EIO; | |
85 | + goto err_free_rx; | |
86 | + } | |
87 | ||
88 | spin_lock_irqsave(&p->port.lock, flags); | |
89 | ||
b9c50d6c | 90 | @@ -911,8 +914,23 @@ static int s3c24xx_serial_request_dma(st |
12ecb97d GKH |
91 | UART_XMIT_SIZE, DMA_TO_DEVICE); |
92 | ||
93 | spin_unlock_irqrestore(&p->port.lock, flags); | |
94 | + if (dma_mapping_error(p->port.dev, dma->tx_addr)) { | |
95 | + ret = -EIO; | |
96 | + goto err_unmap_rx; | |
97 | + } | |
98 | ||
99 | return 0; | |
100 | + | |
101 | +err_unmap_rx: | |
102 | + dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size, | |
103 | + DMA_FROM_DEVICE); | |
104 | +err_free_rx: | |
105 | + kfree(dma->rx_buf); | |
106 | +err_release_tx: | |
107 | + dma_release_channel(dma->tx_chan); | |
108 | +err_release_rx: | |
109 | + dma_release_channel(dma->rx_chan); | |
110 | + return ret; | |
111 | } | |
112 | ||
113 | static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p) |