]> git.baikalelectronics.ru Git - kernel.git/commitdiff
serial: qcom-geni: fix enabling deactivated interrupt
authorKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Fri, 5 May 2023 15:23:01 +0000 (17:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 24 May 2023 16:32:51 +0000 (17:32 +0100)
commit 5f949f140f73696f64acb89a1f16ff9153d017e0 upstream.

The driver have a race, experienced only with PREEMPT_RT patchset:

CPU0                         | CPU1
==================================================================
qcom_geni_serial_probe       |
  uart_add_one_port          |
                             | serdev_drv_probe
                             |   qca_serdev_probe
                             |     serdev_device_open
                             |       uart_open
                             |         uart_startup
                             |           qcom_geni_serial_startup
                             |             enable_irq
                             |               __irq_startup
                             |                 WARN_ON()
                             |                 IRQ not activated
  request_threaded_irq       |
    irq_domain_activate_irq  |

The warning:

  894000.serial: ttyHS1 at MMIO 0x894000 (irq = 144, base_baud = 0) is a MSM
  serial serial0: tty port ttyHS1 registered
  WARNING: CPU: 7 PID: 107 at kernel/irq/chip.c:241 __irq_startup+0x78/0xd8
  ...
  qcom_geni_serial 894000.serial: serial engine reports 0 RX bytes in!

Adding UART port triggers probe of child serial devices - serdev and
eventually Qualcomm Bluetooth hci_qca driver.  This opens UART port
which enables the interrupt before it got activated in
request_threaded_irq().  The issue originates in commit 70e6eaa992a3
("tty: serial: qcom_geni_serial: Wakeup IRQ cleanup") and discussion on
mailing list [1].  However the above commit does not explain why the
uart_add_one_port() is moved above requesting interrupt.

[1] https://lore.kernel.org/all/5d9f3dfa.1c69fb81.84c4b.30bf@mx.google.com/

Fixes: 70e6eaa992a3 ("tty: serial: qcom_geni_serial: Wakeup IRQ cleanup")
Cc: <stable@vger.kernel.org>
Cc: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/20230505152301.2181270-1-krzysztof.kozlowski@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/qcom_geni_serial.c

index 7905935b9f1b4f3c016e0a2bce557feb053b23af..cf9dc2ddfe6644322f8c696ee1768b05001b4b25 100644 (file)
@@ -1483,19 +1483,18 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, port);
        port->handle_rx = console ? handle_rx_console : handle_rx_uart;
 
-       ret = uart_add_one_port(drv, uport);
-       if (ret)
-               return ret;
-
        irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
        ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
                        IRQF_TRIGGER_HIGH, port->name, uport);
        if (ret) {
                dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
-               uart_remove_one_port(drv, uport);
                return ret;
        }
 
+       ret = uart_add_one_port(drv, uport);
+       if (ret)
+               return ret;
+
        /*
         * Set pm_runtime status as ACTIVE so that wakeup_irq gets
         * enabled/disabled from dev_pm_arm_wake_irq during system