serial: stm32: fix probe and remove order for dma
[ Upstream commit87fd0741d6] The probe and remove orders are wrong as the uart_port is registered before saving device data in the probe, and unregistered after DMA resource deallocation in the remove. uart_port registering should be done at the end of probe and unregistering should be done at the begin of remove to avoid resource allocation issues. Fix probe and remove orders. This enforce resource allocation occur at proper time. Terminate both DMA rx and tx transfers before removing device. Move pm_runtime after uart_remove_one_port() call in remove() to keep the probe error path. Fixes:3489187204("serial: stm32: adding dma support") Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com> Link: https://lore.kernel.org/r/20210304162308.8984-2-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
1027c8c028
commit
379b007b57
1 changed files with 44 additions and 13 deletions
|
|
@ -1245,10 +1245,6 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
|
|||
device_set_wakeup_enable(&pdev->dev, false);
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
|
||||
if (ret)
|
||||
goto err_wirq;
|
||||
|
||||
ret = stm32_usart_of_dma_rx_probe(stm32port, pdev);
|
||||
if (ret)
|
||||
dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n");
|
||||
|
|
@ -1262,11 +1258,40 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
|
|||
pm_runtime_get_noresume(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
|
||||
if (ret)
|
||||
goto err_port;
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_wirq:
|
||||
err_port:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
if (stm32port->rx_ch) {
|
||||
dmaengine_terminate_async(stm32port->rx_ch);
|
||||
dma_release_channel(stm32port->rx_ch);
|
||||
}
|
||||
|
||||
if (stm32port->rx_dma_buf)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
RX_BUF_L, stm32port->rx_buf,
|
||||
stm32port->rx_dma_buf);
|
||||
|
||||
if (stm32port->tx_ch) {
|
||||
dmaengine_terminate_async(stm32port->tx_ch);
|
||||
dma_release_channel(stm32port->tx_ch);
|
||||
}
|
||||
|
||||
if (stm32port->tx_dma_buf)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
TX_BUF_L, stm32port->tx_buf,
|
||||
stm32port->tx_dma_buf);
|
||||
|
||||
if (stm32port->wakeirq > 0)
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
|
||||
|
|
@ -1288,11 +1313,20 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||
int err;
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
err = uart_remove_one_port(&stm32_usart_driver, port);
|
||||
if (err)
|
||||
return(err);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||
|
||||
if (stm32_port->rx_ch)
|
||||
if (stm32_port->rx_ch) {
|
||||
dmaengine_terminate_async(stm32_port->rx_ch);
|
||||
dma_release_channel(stm32_port->rx_ch);
|
||||
}
|
||||
|
||||
if (stm32_port->rx_dma_buf)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
|
|
@ -1301,8 +1335,10 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||
|
||||
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
|
||||
|
||||
if (stm32_port->tx_ch)
|
||||
if (stm32_port->tx_ch) {
|
||||
dmaengine_terminate_async(stm32_port->tx_ch);
|
||||
dma_release_channel(stm32_port->tx_ch);
|
||||
}
|
||||
|
||||
if (stm32_port->tx_dma_buf)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
|
|
@ -1316,12 +1352,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||
|
||||
clk_disable_unprepare(stm32_port->clk);
|
||||
|
||||
err = uart_remove_one_port(&stm32_usart_driver, port);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_STM32_CONSOLE
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue