Search Linux Wireless

[PATCH 1/5] mwifiex: access interrupt status only while holding lock

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Avinash Patil <patila@xxxxxxxxxxx>

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@xxxxxxxxxxx>
Signed-off-by: Bing Zhao <bzhao@xxxxxxxxxxx>
---
 drivers/net/wireless/mwifiex/pcie.c |   25 ++++++++++++-------------
 1 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 13fbc4e..e4c2cfd 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -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;
 			}
 
 		}
-- 
1.7.0.2

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux