Hi ath9k team:
Another interest question is since the ath9k interrupt was disabled, how can we 
get a new IRQ to interrupt the tasklet? 
So I investigated and found that the cause of the issue "irq 16: nobody cared" 
in my box is the ath9k's irq handler return 
too many IRQ_NONE since I read the ISR register always return 0 as below.

        /*
         * Figure out the reason(s) for the interrupt.  Note
         * that the hal returns a pseudo-ISR that may include
         * bits we haven't explicitly enabled so we mask the
         * value to insure we only process bits we requested.
         */
        ath9k_hw_getisr(ah, &status);   /* NB: clears ISR too */
        status &= ah->imask;    /* discard unasked-for bits */

        /*
         * If there are no status bits set, then this interrupt was not
         * for me (should have been caught above).
         */
        if (!status) 
                return IRQ_NONE;

if I go to reset chip instead of return IRQ_NONE in this position, the things 
become a little healthier than before, 
I will never see the message "irq 16: nobody cared".

I check each IRQ using "if(AR_SREV_9300(ah))" and they are all passed, that is, 
no other hardware share the irq with ath9k.
I need to know why we read the ISR register and get value 0, and return 
IRQ_NONE, the chip I used is AR9300.
Can we using this change below in the ath_isr() function:
        if (!status) 
                goto reset_chip;

Thanks,
- Felix
-----
From: Felix Liao 
Sent: Friday, November 09, 2012 9:33 AM
To: 'ath9k-devel@lists.ath9k.org'
Subject: ath9k_tasklet() can be interrupted by a hardware IRQ

Hi all,
I met a kernel call trace below using the ath9k driver, we can see that the 
ath9k_tasklet() was interrupted by a hardware IRQ, 
and at this time the ath9k IRQ was disabled, so the kernel will complain that 
there is none irq handler for this interrupt.

[   60.977474] irq 16: nobody cared (try booting with the "irqpoll" option)
[   60.984194] Call Trace:
[   60.986660] [dfff1f50] [c000843c] show_stack+0x70/0x1c8 (unreliable)
[   60.993041] [dfff1f90] [c00777a0] __report_bad_irq+0x44/0xe8
[   60.998718] [dfff1fb0] [c0077a44] note_interrupt+0x200/0x260
[   61.004396] [dfff1fe0] [c0078704] handle_fasteoi_irq+0xc4/0x10c
[   61.010340] [dfff1ff0] [c0010fdc] call_handle_irq+0x18/0x28
[   61.015929] [dfff3e50] [c00051c8] do_IRQ+0xcc/0x1b4
[   61.020825] [dfff3e80] [c0011fc4] ret_from_except+0x0/0x18
[   61.026349] --- Exception: 501 at ioread32+0x8/0x14
[   61.026355]     LR = ath_descdma_setup+0x294/0x664 [ath9k]
[   61.036733] [dfff3f40] [c04f5bdc] softirq_to_name+0x0/0x28 (unreliable)
[   61.043390] [dfff3f50] [e5ad66fc] ath9k_hw_enable_interrupts+0x160/0x1b0 
[ath9k_hw]
[   61.051074] [dfff3f70] [e5b41368] ath9k_tasklet+0xc0/0x208 [ath9k]
[   61.057274] [dfff3f90] [c0043298] tasklet_action+0xcc/0xf8
[   61.062777] [dfff3fb0] [c0043d48] __do_softirq+0xdc/0x18c
[   61.068194] [dfff3ff0] [c0010fb4] call_do_softirq+0x14/0x24
[   61.073784] [d8613e60] [c0004fec] do_softirq+0x8c/0x98
[   61.078939] [d8613e80] [c0043bd0] local_bh_enable+0x9c/0xa0
[   61.084536] [d8613e90] [c036d910] unix_create1+0x184/0x1ac
[   61.090039] [d8613eb0] [c036d9a0] unix_create+0x68/0xbc
[   61.095286] [d8613ec0] [c02c6c34] __sock_create+0x114/0x248
[   61.100877] [d8613ef0] [c02c7008] sys_socket+0x54/0x84
[   61.106031] [d8613f10] [c02c70e8] sys_socketcall+0xb0/0x258
[   61.111622] [d8613f40] [c0011970] ret_from_syscall+0x0/0x3c
[   61.117338] --- Exception: c01 at 0xeff41fc
[   61.117343]     LR = 0xeff4350
[   61.124578] handlers:
[   61.126851] [<e5b3eb44>] (ath_isr+0x0/0x21c [ath9k])
[   61.131840] Disabling IRQ #16
[   61.143234] ath: phy0: Failed to stop TX DMA, queues=0x001!

I made a patch below for this issue and use it to reduce the probability of 
this issue, you can see that, 
I can't disable the IRQ from start to end of this function, I need to restore 
the IRQ flags before we call ath_rx_tasklet and ath_tx_tasklet, 
since these functions will disable and enable the local softirq using 
spin_lock_bh and spin_unlock_bh,  since with this gap of time, 
the tasklet still can be interrupted by the hardware IRQ.

diff -pNaur compat-wireless-3.6.6-1-orig/drivers/net/wireless/ath/ath9k/main.c 
compat-wireless-3.6.6-1-fixed/drivers/net/wireless/ath/ath9k/main.c
--- compat-wireless-3.6.6-1-orig/drivers/net/wireless/ath/ath9k/main.c    
2012-11-08 00:17:08.000000000 +0800
+++ 
compat-wireless-3.6.6-1-fixed/drivers/net/wireless/ath/ath9k/main.c              
 2012-11-09 07:27:28.459837051 +0800
@@ -368,6 +368,7 @@ void ath9k_tasklet(unsigned long data)
              u32 status = sc->intrstatus;
              u32 rxmask;

+             local_irq_save(flags);
              ath9k_ps_wakeup(sc);
              spin_lock(&sc->sc_pcu_lock);

@@ -383,7 +384,7 @@ void ath9k_tasklet(unsigned long data)
                             goto out;
              }

-              spin_lock_irqsave(&sc->sc_pm_lock, flags);
+             spin_lock(&sc->sc_pm_lock);
              if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                             /*
                              * TSF sync does not look correct; remain awake to 
sync with
@@ -392,7 +393,7 @@ void ath9k_tasklet(unsigned long data)
                             ath_dbg(common, PS, "TSFOOR - Sync with next 
Beacon\n");
                             sc->ps_flags |= PS_WAIT_FOR_BEACON | 
PS_BEACON_SYNC;
              }
-              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+             spin_unlock(&sc->sc_pm_lock);

               if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                             rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | 
ATH9K_INT_RXEOL |
@@ -400,6 +401,7 @@ void ath9k_tasklet(unsigned long data)
              else
                             rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | 
ATH9K_INT_RXORN);

+             local_irq_restore(flags);
              if (status & rxmask) {
                             /* Check for high priority Rx first */
                             if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
@@ -416,6 +418,7 @@ void ath9k_tasklet(unsigned long data)
                                            ath_tx_tasklet(sc);
              }

+             local_irq_save(flags);
              ath9k_btcoex_handle_interrupt(sc, status);

 out:
@@ -424,6 +427,7 @@ out:

               spin_unlock(&sc->sc_pcu_lock);
              ath9k_ps_restore(sc);
+             local_irq_restore(flags);
}

 irqreturn_t ath_isr(int irq, void *dev)

but what I need to say is we should disable the IRQ entire of this function, so 
we need to use the 
spin_lock/spin_unlock instead of spin_lock_bh/spin_unlock_bh in the functions 
called by it, 
but I know it is a big job to do, so I ask for your suggestion.
In a simple way,  this patch can fix this issue incompletely.

Thanks,
- Felix

_______________________________________________
ath9k-devel mailing list
ath9k-devel@lists.ath9k.org
https://lists.ath9k.org/mailman/listinfo/ath9k-devel

Reply via email to