Skip to content

Commit

Permalink
ath9k: Use atomic reference count for interrupt ops
Browse files Browse the repository at this point in the history
Let us enable/disable interrupts based on reference count.
By doing this we can ensure that interrupts are never be
enabled in the middle of tasklet processing. Instead of
addressing corner cases like "ath9k: avoid enabling interrupts
while processing rx", this approach handles it in generic manner.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Rajkumar Manoharan authored and John W. Linville committed Aug 9, 2011
1 parent a844adf commit e8fe733
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 21 deletions.
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,6 @@ struct ath_ant_comb {
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
#define PS_WAIT_FOR_TX_ACK BIT(3)
#define PS_BEACON_SYNC BIT(4)
#define PS_TSFOOR_SYNC BIT(5)

struct ath_rate_table;

Expand Down
21 changes: 5 additions & 16 deletions drivers/net/wireless/ath/ath9k/beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,14 +649,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
ath9k_hw_set_sta_beacon_timers(ah, &bs);
ah->imask |= ATH9K_INT_BMISS;

/*
* If the beacon config is called beacause of TSFOOR,
* Interrupts will be enabled back at the end of ath9k_tasklet
*/
if (!(sc->ps_flags & PS_TSFOOR_SYNC)) {
ath9k_hw_set_interrupts(ah, ah->imask);
ath9k_hw_enable_interrupts(ah);
}
ath9k_hw_set_interrupts(ah, ah->imask);
ath9k_hw_enable_interrupts(ah);
}

static void ath_beacon_config_adhoc(struct ath_softc *sc,
Expand Down Expand Up @@ -690,14 +684,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
/*
* If the beacon config is called beacause of TSFOOR,
* Interrupts will be enabled back at the end of ath9k_tasklet
*/
if (!(sc->ps_flags & PS_TSFOOR_SYNC)) {
ath9k_hw_set_interrupts(ah, ah->imask);
ath9k_hw_enable_interrupts(ah);
}

ath9k_hw_set_interrupts(ah, ah->imask);
ath9k_hw_enable_interrupts(ah);
}

static bool ath9k_allow_beacon_config(struct ath_softc *sc,
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath9k/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ struct ath_hw {
u32 txdesc_interrupt_mask;
u32 txeol_interrupt_mask;
u32 txurn_interrupt_mask;
atomic_t intr_ref_cnt;
bool chip_fullsleep;
u32 atim_window;

Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath9k/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->reg_ops.read = ath9k_ioread32;
ah->reg_ops.write = ath9k_iowrite32;
ah->reg_ops.rmw = ath9k_reg_rmw;
atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah;

if (!pdata) {
Expand Down
13 changes: 12 additions & 1 deletion drivers/net/wireless/ath/ath9k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);

if (!(ah->imask & ATH9K_INT_GLOBAL))
atomic_set(&ah->intr_ref_cnt, -1);
else
atomic_dec(&ah->intr_ref_cnt);

ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
Expand All @@ -821,6 +826,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
if (!(ah->imask & ATH9K_INT_GLOBAL))
return;

if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
ath_dbg(common, ATH_DBG_INTERRUPT,
"Do not enable IER ref count %d\n",
atomic_read(&ah->intr_ref_cnt));
return;
}

if (AR_SREV_9340(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;

Expand Down Expand Up @@ -852,7 +864,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)

ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);

/* TODO: global int Ref count */
mask = ints & ATH9K_INT_COMMON;
mask2 = 0;

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,8 +707,7 @@ void ath9k_tasklet(unsigned long data)
*/
ath_dbg(common, ATH_DBG_PS,
"TSFOOR - Sync with next Beacon\n");
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
PS_TSFOOR_SYNC;
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
}

if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
Expand Down Expand Up @@ -887,6 +886,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)

ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
atomic_set(&ah->intr_ref_cnt, -1);

ath9k_hw_configpcipowersave(ah, 0, 0);

Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath9k/recv.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
ath_dbg(common, ATH_DBG_PS,
"Reconfigure Beacon timers based on timestamp from the AP\n");
ath_set_beacon(sc);
sc->ps_flags &= ~PS_TSFOOR_SYNC;
}

if (ath_beacon_dtim_pending_cab(skb)) {
Expand Down

0 comments on commit e8fe733

Please sign in to comment.