Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 659c4788 authored by Avinash Patil's avatar Avinash Patil Committed by John W. Linville
Browse files

mwifiex: access interrupt status only while holding lock



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: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarBing Zhao <bzhao@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 6ba1eafe
Loading
Loading
Loading
Loading
+12 −13
Original line number Diff line number Diff line
@@ -1594,39 +1594,40 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
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;
			}

		}