serial: tegra-tcu: Reorder channel initialization
authorMikko Perttunen <mperttunen@nvidia.com>
Wed, 9 Jun 2021 15:56:55 +0000 (18:56 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Jun 2021 12:02:06 +0000 (14:02 +0200)
Request the RX mailbox only after initializing the UART data
structures. Otherwise it can rarely happen that the receive
callback is called before the UART is ready.

Fixes: 2d908b38d409 ("serial: Add Tegra Combined UART driver")
Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Link: https://lore.kernel.org/r/20210609155655.3567545-1-mperttunen@nvidia.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/tegra-tcu.c

index 52687c65ad7455e18c0795001e3c5e945a42bda9..4877c54c613d1f0d899855350b1e9a81a1a001df 100644 (file)
@@ -195,13 +195,6 @@ static int tegra_tcu_probe(struct platform_device *pdev)
                return err;
        }
 
-       tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
-       if (IS_ERR(tcu->rx)) {
-               err = PTR_ERR(tcu->rx);
-               dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
-               goto free_tx;
-       }
-
 #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
        /* setup the console */
        strcpy(tcu->console.name, "ttyTCU");
@@ -226,7 +219,7 @@ static int tegra_tcu_probe(struct platform_device *pdev)
        if (err) {
                dev_err(&pdev->dev, "failed to register UART driver: %d\n",
                        err);
-               goto free_rx;
+               goto free_tx;
        }
 
        /* setup the port */
@@ -246,6 +239,17 @@ static int tegra_tcu_probe(struct platform_device *pdev)
                goto unregister_uart;
        }
 
+       /*
+        * Request RX channel after creating port to ensure tcu->port
+        * is ready for any immediate incoming bytes.
+        */
+       tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
+       if (IS_ERR(tcu->rx)) {
+               err = PTR_ERR(tcu->rx);
+               dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
+               goto remove_uart_port;
+       }
+
        platform_set_drvdata(pdev, tcu);
 #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
        register_console(&tcu->console);
@@ -253,10 +257,10 @@ static int tegra_tcu_probe(struct platform_device *pdev)
 
        return 0;
 
+remove_uart_port:
+       uart_remove_one_port(&tcu->driver, &tcu->port);
 unregister_uart:
        uart_unregister_driver(&tcu->driver);
-free_rx:
-       mbox_free_channel(tcu->rx);
 free_tx:
        mbox_free_channel(tcu->tx);
 
@@ -270,9 +274,9 @@ static int tegra_tcu_remove(struct platform_device *pdev)
 #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
        unregister_console(&tcu->console);
 #endif
+       mbox_free_channel(tcu->rx);
        uart_remove_one_port(&tcu->driver, &tcu->port);
        uart_unregister_driver(&tcu->driver);
-       mbox_free_channel(tcu->rx);
        mbox_free_channel(tcu->tx);
 
        return 0;