Commit 4df3071e authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

ath9k_hw: optimize interrupt mask changes

OProfile showed that ath9k was spending way too much time in
ath9k_hw_set_interrupts. Since most of the interrupt mask changes only
need to globally enable/disable interrupts, it makes sense to split
this part into separate functions, replacing all calls to
ath9k_hw_set_interrupts(ah, 0) with ath9k_hw_disable_interrupts(ah).

ath9k_hw_set_interrupts(ah, ah->imask) only gets changed to
ath9k_hw_enable_interrupts(ah), whenever ah->imask was not changed
since the point where interrupts were disabled.
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 790a11f2
...@@ -503,7 +503,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, ...@@ -503,7 +503,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */ /* Set the computed AP beacon timers */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval); ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0; sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_set_interrupts(ah, ah->imask);
...@@ -638,7 +638,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, ...@@ -638,7 +638,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
/* Set the computed STA beacon timers */ /* Set the computed STA beacon timers */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ath9k_hw_set_sta_beacon_timers(ah, &bs); ath9k_hw_set_sta_beacon_timers(ah, &bs);
ah->imask |= ATH9K_INT_BMISS; ah->imask |= ATH9K_INT_BMISS;
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_set_interrupts(ah, ah->imask);
...@@ -686,7 +686,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ...@@ -686,7 +686,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
/* Set the computed ADHOC beacon timers */ /* Set the computed ADHOC beacon timers */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval); ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0; sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_set_interrupts(ah, ah->imask);
......
...@@ -259,7 +259,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, ...@@ -259,7 +259,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ah->imask |= ATH9K_INT_GENTIMER; ah->imask |= ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_set_interrupts(ah, ah->imask);
} }
...@@ -273,7 +273,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) ...@@ -273,7 +273,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
/* if no timer is enabled, turn off interrupt mask */ /* if no timer is enabled, turn off interrupt mask */
if (timer_table->timer_mask.val == 0) { if (timer_table->timer_mask.val == 0) {
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ah->imask &= ~ATH9K_INT_GENTIMER; ah->imask &= ~ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_set_interrupts(ah, ah->imask);
} }
......
...@@ -117,12 +117,11 @@ EXPORT_SYMBOL(ath9k_hw_numtxpending); ...@@ -117,12 +117,11 @@ EXPORT_SYMBOL(ath9k_hw_numtxpending);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
{ {
u32 txcfg, curLevel, newLevel; u32 txcfg, curLevel, newLevel;
enum ath9k_int omask;
if (ah->tx_trig_level >= ah->config.max_txtrig_level) if (ah->tx_trig_level >= ah->config.max_txtrig_level)
return false; return false;
omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL); ath9k_hw_disable_interrupts(ah);
txcfg = REG_READ(ah, AR_TXCFG); txcfg = REG_READ(ah, AR_TXCFG);
curLevel = MS(txcfg, AR_FTRIG); curLevel = MS(txcfg, AR_FTRIG);
...@@ -136,7 +135,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) ...@@ -136,7 +135,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
REG_WRITE(ah, AR_TXCFG, REG_WRITE(ah, AR_TXCFG,
(txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
ath9k_hw_set_interrupts(ah, omask); ath9k_hw_enable_interrupts(ah);
ah->tx_trig_level = newLevel; ah->tx_trig_level = newLevel;
...@@ -849,28 +848,59 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) ...@@ -849,28 +848,59 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
} }
EXPORT_SYMBOL(ath9k_hw_intrpend); EXPORT_SYMBOL(ath9k_hw_intrpend);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, void ath9k_hw_disable_interrupts(struct ath_hw *ah)
enum ath9k_int ints) {
struct ath_common *common = ath9k_hw_common(ah);
ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
(void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
(void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
}
}
EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
void ath9k_hw_enable_interrupts(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
if (!(ah->imask & ATH9K_INT_GLOBAL))
return;
ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
AR_INTR_MAC_IRQ);
REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
AR_INTR_SYNC_DEFAULT);
REG_WRITE(ah, AR_INTR_SYNC_MASK,
AR_INTR_SYNC_DEFAULT);
}
ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
}
EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
{ {
enum ath9k_int omask = ah->imask; enum ath9k_int omask = ah->imask;
u32 mask, mask2; u32 mask, mask2;
struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); if (!(ints & ATH9K_INT_GLOBAL))
ath9k_hw_enable_interrupts(ah);
if (omask & ATH9K_INT_GLOBAL) {
ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
(void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
(void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
}
}
/* TODO: global int Ref count */ /* TODO: global int Ref count */
mask = ints & ATH9K_INT_COMMON; mask = ints & ATH9K_INT_COMMON;
...@@ -946,24 +976,8 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, ...@@ -946,24 +976,8 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
} }
if (ints & ATH9K_INT_GLOBAL) { ath9k_hw_enable_interrupts(ah);
ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
AR_INTR_MAC_IRQ);
REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
AR_INTR_SYNC_DEFAULT);
REG_WRITE(ah, AR_INTR_SYNC_MASK,
AR_INTR_SYNC_DEFAULT);
}
ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
}
return omask; return;
} }
EXPORT_SYMBOL(ath9k_hw_set_interrupts); EXPORT_SYMBOL(ath9k_hw_set_interrupts);
...@@ -669,6 +669,7 @@ enum ath9k_key_type { ...@@ -669,6 +669,7 @@ enum ath9k_key_type {
struct ath_hw; struct ath_hw;
struct ath9k_channel; struct ath9k_channel;
enum ath9k_int;
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
...@@ -700,8 +701,9 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah); ...@@ -700,8 +701,9 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah);
/* Interrupt Handling */ /* Interrupt Handling */
bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_intrpend(struct ath_hw *ah);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
enum ath9k_int ints); void ath9k_hw_enable_interrupts(struct ath_hw *ah);
void ath9k_hw_disable_interrupts(struct ath_hw *ah);
void ar9002_hw_attach_mac_ops(struct ath_hw *ah); void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
......
...@@ -239,7 +239,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ...@@ -239,7 +239,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
* hardware at the new frequency, and then re-enable * hardware at the new frequency, and then re-enable
* the relevant bits of the h/w. * the relevant bits of the h/w.
*/ */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ath_drain_all_txq(sc, false); ath_drain_all_txq(sc, false);
spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->rx.pcu_lock);
...@@ -653,7 +653,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -653,7 +653,7 @@ void ath9k_tasklet(unsigned long data)
ath_gen_timer_isr(sc->sc_ah); ath_gen_timer_isr(sc->sc_ah);
/* re-enable hardware interrupt */ /* re-enable hardware interrupt */
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_enable_interrupts(ah);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
} }
...@@ -752,7 +752,7 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -752,7 +752,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* interrupt; otherwise it will continue to * interrupt; otherwise it will continue to
* fire. * fire.
*/ */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
/* /*
* Let the hal handle the event. We assume * Let the hal handle the event. We assume
* it will clear whatever condition caused * it will clear whatever condition caused
...@@ -761,7 +761,7 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -761,7 +761,7 @@ irqreturn_t ath_isr(int irq, void *dev)
spin_lock(&common->cc_lock); spin_lock(&common->cc_lock);
ath9k_hw_proc_mib_event(ah); ath9k_hw_proc_mib_event(ah);
spin_unlock(&common->cc_lock); spin_unlock(&common->cc_lock);
ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_enable_interrupts(ah);
} }
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
...@@ -778,8 +778,8 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -778,8 +778,8 @@ irqreturn_t ath_isr(int irq, void *dev)
ath_debug_stat_interrupt(sc, status); ath_debug_stat_interrupt(sc, status);
if (sched) { if (sched) {
/* turn off every interrupt except SWBA */ /* turn off every interrupt */
ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA)); ath9k_hw_disable_interrupts(ah);
tasklet_schedule(&sc->intr_tq); tasklet_schedule(&sc->intr_tq);
} }
...@@ -937,7 +937,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -937,7 +937,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
} }
/* Disable interrupts */ /* Disable interrupts */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ath_drain_all_txq(sc, false); /* clear pending tx frames */ ath_drain_all_txq(sc, false); /* clear pending tx frames */
...@@ -980,7 +980,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ...@@ -980,7 +980,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
ieee80211_stop_queues(hw); ieee80211_stop_queues(hw);
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
ath_drain_all_txq(sc, retry_tx); ath_drain_all_txq(sc, retry_tx);
spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->rx.pcu_lock);
...@@ -1394,7 +1394,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ...@@ -1394,7 +1394,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
/* make sure h/w will not generate any interrupt /* make sure h/w will not generate any interrupt
* before setting the invalid flag. */ * before setting the invalid flag. */
ath9k_hw_set_interrupts(ah, 0); ath9k_hw_disable_interrupts(ah);
spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->rx.pcu_lock);
if (!(sc->sc_flags & SC_OP_INVALID)) { if (!(sc->sc_flags & SC_OP_INVALID)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment