diff mbox series

[13/16] wil6210: ignore HALP ICR if already handled

Message ID 1540975944-30576-14-git-send-email-merez@codeaurora.org (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series wil6210 patches | expand

Commit Message

Maya Erez Oct. 31, 2018, 8:52 a.m. UTC
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 an atomic flag to indicate if HALP ICR should be handled.

Signed-off-by: Maya Erez <merez@codeaurora.org>
---
 drivers/net/wireless/ath/wil6210/interrupt.c | 10 +++++++---
 drivers/net/wireless/ath/wil6210/main.c      |  2 ++
 drivers/net/wireless/ath/wil6210/wil6210.h   |  1 +
 3 files changed, 10 insertions(+), 3 deletions(-)

Comments

Kalle Valo Nov. 6, 2018, 10:04 a.m. UTC | #1
Maya Erez <merez@codeaurora.org> writes:

> 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 an atomic flag to indicate if HALP ICR should be handled.
>
> Signed-off-by: Maya Erez <merez@codeaurora.org>

[...]

> --- a/drivers/net/wireless/ath/wil6210/interrupt.c
> +++ b/drivers/net/wireless/ath/wil6210/interrupt.c
> @@ -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 (atomic_read(&wil->halp.handle_icr)) {
> +			/* no need to handle HALP ICRs until next vote */
> +			atomic_set(&wil->halp.handle_icr, 0);

atomic_read() followed by atomic_set() is IMHO not really atomic :) I
would assume there's a function to reset the variable really in atomic
way.
Maya Erez Nov. 6, 2018, 12:24 p.m. UTC | #2
On 2018-11-06 12:04, Kalle Valo wrote:
> Maya Erez <merez@codeaurora.org> writes:
> 
>> 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 an atomic flag to indicate if HALP ICR should be handled.
>> 
>> Signed-off-by: Maya Erez <merez@codeaurora.org>
> 
> [...]
> 
>> --- a/drivers/net/wireless/ath/wil6210/interrupt.c
>> +++ b/drivers/net/wireless/ath/wil6210/interrupt.c
>> @@ -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 (atomic_read(&wil->halp.handle_icr)) {
>> +			/* no need to handle HALP ICRs until next vote */
>> +			atomic_set(&wil->halp.handle_icr, 0);
> 
> atomic_read() followed by atomic_set() is IMHO not really atomic :) I
> would assume there's a function to reset the variable really in atomic
> way.

Actually it shouldn't be atomic :-)
I'll remove it.
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 5d287a8..a58fccb 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -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 (atomic_read(&wil->halp.handle_icr)) {
+			/* no need to handle HALP ICRs until next vote */
+			atomic_set(&wil->halp.handle_icr, 0);
+			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 5303867..5c89c01 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1922,6 +1922,8 @@  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 */
+		atomic_set(&wil->halp.handle_icr, 1);
 		wil6210_set_halp(wil);
 		rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
 		if (!rc) {
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 0f3be3ff..1897d8c 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -791,6 +791,7 @@  struct wil_halp {
 	struct mutex		lock; /* protect halp ref_cnt */
 	unsigned int		ref_cnt;
 	struct completion	comp;
+	atomic_t		handle_icr;
 };
 
 struct wil_blob_wrapper {