HALP ICR is set as long as the FW should stay awake.
To prevent its multiple handling the driver masks this IRQ bit.
However, if there is a different MISC ICR before the driver clears
this bit, there is a risk of race condition between HALP mask and
unmask. This race leads to HALP timeout, in case it is mistakenly
masked.
Add a flag to indicate if HALP ICR should be handled.

Signed-off-by: Maya Erez <[email protected]>
---
 drivers/net/wireless/ath/wil6210/interrupt.c | 12 ++++++++----
 drivers/net/wireless/ath/wil6210/main.c      |  3 +++
 drivers/net/wireless/ath/wil6210/wil6210.h   |  1 +
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c 
b/drivers/net/wireless/ath/wil6210/interrupt.c
index 5d287a8..3f5bd17 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -575,10 +575,14 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
        }
 
        if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
-               wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
-               wil6210_mask_halp(wil);
                isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
-               complete(&wil->halp.comp);
+               if (wil->halp.handle_icr) {
+                       /* no need to handle HALP ICRs until next vote */
+                       wil->halp.handle_icr = false;
+                       wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
+                       wil6210_mask_halp(wil);
+                       complete(&wil->halp.comp);
+               }
        }
 
        wil->isr_misc = isr;
diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index 1c2823b..bd933a0 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1899,11 +1899,14 @@ void wil_halp_vote(struct wil6210_priv *wil)
 
        if (++wil->halp.ref_cnt == 1) {
                reinit_completion(&wil->halp.comp);
+               /* mark to IRQ context to handle HALP ICR */
+               wil->halp.handle_icr = true;
                wil6210_set_halp(wil);
                rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
                if (!rc) {
                        wil_err(wil, "HALP vote timed out\n");
                        /* Mask HALP as done in case the interrupt is raised */
+                       wil->halp.handle_icr = false;
                        wil6210_mask_halp(wil);
                } else {
                        wil_dbg_irq(wil,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h 
b/drivers/net/wireless/ath/wil6210/wil6210.h
index cc46873..de97c4e 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -781,6 +781,7 @@ struct wil_halp {
        struct mutex            lock; /* protect halp ref_cnt */
        unsigned int            ref_cnt;
        struct completion       comp;
+       u8                      handle_icr;
 };
 
 struct wil_blob_wrapper {
-- 
1.9.1

Reply via email to