mwifiex: access interrupt status only while holding lock
authorAvinash Patil <patila@marvell.com>
Fri, 4 Jan 2013 05:21:28 +0000 (21:21 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 7 Jan 2013 20:18:29 +0000 (15:18 -0500)
This patch fixes a bug for few instances where PCIe interrupt
status variable is accessed without holding spin lock.
This can result into missing interrupts.

Fix this by copying interrupt status to a local variable and
then using it for calling specific routine.

Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/pcie.c

index 13fbc4eb15952fe375be1e10c55518bb2b6b3836..e4c2cfdd049c72049f168de2ad1fd63119857019 100644 (file)
@@ -1594,39 +1594,40 @@ exit:
 static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
 {
        int ret;
-       u32 pcie_ireg = 0;
+       u32 pcie_ireg;
        unsigned long flags;
 
        spin_lock_irqsave(&adapter->int_lock, flags);
        /* Clear out unused interrupts */
-       adapter->int_status &= HOST_INTR_MASK;
+       pcie_ireg = adapter->int_status;
+       adapter->int_status = 0;
        spin_unlock_irqrestore(&adapter->int_lock, flags);
 
-       while (adapter->int_status & HOST_INTR_MASK) {
-               if (adapter->int_status & HOST_INTR_DNLD_DONE) {
-                       adapter->int_status &= ~HOST_INTR_DNLD_DONE;
+       while (pcie_ireg & HOST_INTR_MASK) {
+               if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+                       pcie_ireg &= ~HOST_INTR_DNLD_DONE;
                        if (adapter->data_sent) {
                                dev_dbg(adapter->dev, "info: DATA sent intr\n");
                                adapter->data_sent = false;
                        }
                }
-               if (adapter->int_status & HOST_INTR_UPLD_RDY) {
-                       adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+               if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+                       pcie_ireg &= ~HOST_INTR_UPLD_RDY;
                        dev_dbg(adapter->dev, "info: Rx DATA\n");
                        ret = mwifiex_pcie_process_recv_data(adapter);
                        if (ret)
                                return ret;
                }
-               if (adapter->int_status & HOST_INTR_EVENT_RDY) {
-                       adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+               if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+                       pcie_ireg &= ~HOST_INTR_EVENT_RDY;
                        dev_dbg(adapter->dev, "info: Rx EVENT\n");
                        ret = mwifiex_pcie_process_event_ready(adapter);
                        if (ret)
                                return ret;
                }
 
-               if (adapter->int_status & HOST_INTR_CMD_DONE) {
-                       adapter->int_status &= ~HOST_INTR_CMD_DONE;
+               if (pcie_ireg & HOST_INTR_CMD_DONE) {
+                       pcie_ireg &= ~HOST_INTR_CMD_DONE;
                        if (adapter->cmd_sent) {
                                dev_dbg(adapter->dev,
                                        "info: CMD sent Interrupt\n");
@@ -1654,8 +1655,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
                                                 "Write register failed\n");
                                        return -1;
                                }
-                               adapter->int_status |= pcie_ireg;
-                               adapter->int_status &= HOST_INTR_MASK;
                        }
 
                }