| From 90f04c2926cfb5bf74533b0a7766bc896f6a0c0e Mon Sep 17 00:00:00 2001 |
| From: Tomoya MORINAGA <tomoya.rohm@gmail.com> |
| Date: Fri, 11 Nov 2011 10:55:27 +0900 |
| Subject: pch_uart: Fix DMA resource leak issue |
| |
| From: Tomoya MORINAGA <tomoya.rohm@gmail.com> |
| |
| commit 90f04c2926cfb5bf74533b0a7766bc896f6a0c0e upstream. |
| |
| Changing UART mode PIO->DMA->PIO->DMA like below, pch_uart driver can't get |
| DMA channel resource. |
| |
| setserial /dev/ttyPCH0 ^low_latency |
| setserial /dev/ttyPCH0 low_latency |
| |
| CAUSE: |
| Changing mode using setserial command, ".startup" function which gets DMA |
| channel is called before ".verify_port" function which sets |
| dma-flag(use_dma/use_dma_flag) as 1. |
| |
| PIO->DMA |
| .startup: Since dma-flag is 0, DMA channel is not requested. |
| .verify_port: dma-flag is set as 1. |
| .shutdown: N/A |
| |
| DMA->PIO |
| .startup: Since dma-flag is 1, DMA channel is requested. |
| .verify_port: dma-flag is set as 0. |
| .shutdown: Since dma-flag is 0, DMA channel is not released. |
| |
| This means DMA channel resource leak occurs. |
| Next time, this driver can't get DMA channel resource forever. |
| |
| MODIFICATION: |
| Currently, when release DMA channel resource, this driver checks dma-flag. |
| However, this specification occurs the above issue. |
| This driver must check whether dma_request_channel is executed or not. |
| The values are saved in private data variable "chan_tx/chan_tx". |
| These variables mean if the value is NULL, DMA channel is not requested, |
| if not NULL, DMA channel is requested. |
| |
| This patch fixes the issue. |
| |
| Signed-off-by: Tomoya MORINAGA <tomoya.rohm@gmail.com> |
| Acked-by: Alan Cox <alan@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/tty/serial/pch_uart.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/tty/serial/pch_uart.c |
| +++ b/drivers/tty/serial/pch_uart.c |
| @@ -625,6 +625,7 @@ static void pch_request_dma(struct uart_ |
| dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", |
| __func__); |
| dma_release_channel(priv->chan_tx); |
| + priv->chan_tx = NULL; |
| return; |
| } |
| |
| @@ -1212,8 +1213,7 @@ static void pch_uart_shutdown(struct uar |
| dev_err(priv->port.dev, |
| "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); |
| |
| - if (priv->use_dma_flag) |
| - pch_free_dma(port); |
| + pch_free_dma(port); |
| |
| free_irq(priv->port.irq, priv); |
| } |