Bluetooth: btintel_pcie: Add additional to checks to clear TX/RX paths
authorKiran K <kiran.k@intel.com>
Sun, 20 Apr 2025 01:51:56 +0000 (07:21 +0530)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 25 Apr 2025 19:03:19 +0000 (15:03 -0400)
Due to a hardware issue, there is a possibility that the driver may miss
an MSIx interrupt on the RX/TX data path. Since the TX and RX paths are
independent, when a TX MSIx interrupt occurs, the driver can check the
RX queue for any pending data and process it if present. The same
approach applies to the RX path.

Fixes: c2b636b3f788 ("Bluetooth: btintel_pcie: Add support for PCIe transport")
Signed-off-by: Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/btintel_pcie.c

index efe6ad6d4dc0f8a6e60f0a2853c81f35062abef8..0a759ea26fd38f600ae9644842c46ebe95a3db54 100644 (file)
@@ -1272,10 +1272,8 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
        bt_dev_dbg(hdev, "RXQ: cr_hia: %u  cr_tia: %u", cr_hia, cr_tia);
 
        /* Check CR_TIA and CR_HIA for change */
-       if (cr_tia == cr_hia) {
-               bt_dev_warn(hdev, "RXQ: no new CD found");
+       if (cr_tia == cr_hia)
                return;
-       }
 
        rxq = &data->rxq;
 
@@ -1311,6 +1309,16 @@ static irqreturn_t btintel_pcie_msix_isr(int irq, void *data)
        return IRQ_WAKE_THREAD;
 }
 
+static inline bool btintel_pcie_is_rxq_empty(struct btintel_pcie_data *data)
+{
+       return data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM] == data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM];
+}
+
+static inline bool btintel_pcie_is_txackq_empty(struct btintel_pcie_data *data)
+{
+       return data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] == data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM];
+}
+
 static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
 {
        struct msix_entry *entry = dev_id;
@@ -1342,12 +1350,18 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
                btintel_pcie_msix_gp0_handler(data);
 
        /* For TX */
-       if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0)
+       if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0) {
                btintel_pcie_msix_tx_handle(data);
+               if (!btintel_pcie_is_rxq_empty(data))
+                       btintel_pcie_msix_rx_handle(data);
+       }
 
        /* For RX */
-       if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1)
+       if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1) {
                btintel_pcie_msix_rx_handle(data);
+               if (!btintel_pcie_is_txackq_empty(data))
+                       btintel_pcie_msix_tx_handle(data);
+       }
 
        /*
         * Before sending the interrupt the HW disables it to prevent a nested