From f749b94679c71a9c74ad9509dbbf00d8f3d620ad Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 28 Jul 2011 14:08:57 +0200 Subject: ath9k: use the new channel noise value for signal strength and survey info Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9098aaad97a..b602447b0a8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -163,7 +163,7 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel) if (chan->noisefloor) { survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = chan->noisefloor; + survey->noise = ath9k_hw_getchan_noise(ah, chan); } } -- cgit v1.2.3-70-g09d2 From b037b693265e5c83ddc3f003a713d19b9832bf24 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 5 Aug 2011 18:59:40 +0530 Subject: ath9k: do not enable interrupt on set interrupt mask At preset set_interrupt also enables interrupt after changing mask. This is not necessary in all cases and also sometime it breaks the assumption that interrupt was disabled. So let us enable the interrupt explicity if it was disabled earlier. This could also avoid unnecessary register ops and also helps the follow up patch to have global ref count for interrupts ops. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 9 +++++++-- drivers/net/wireless/ath/ath9k/gpio.c | 2 ++ drivers/net/wireless/ath/ath9k/mac.c | 3 --- drivers/net/wireless/ath/ath9k/main.c | 4 ++++ 4 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0d13ff74a68..f1d66abc367 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -522,6 +522,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); } /* @@ -652,8 +653,10 @@ static void ath_beacon_config_sta(struct ath_softc *sc, * 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)) + if (!(sc->ps_flags & PS_TSFOOR_SYNC)) { ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); + } } static void ath_beacon_config_adhoc(struct ath_softc *sc, @@ -691,8 +694,10 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * 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)) + if (!(sc->ps_flags & PS_TSFOOR_SYNC)) { ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); + } } static bool ath9k_allow_beacon_config(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index bc713fc2819..5113dd80c99 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -149,6 +149,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, ath9k_hw_disable_interrupts(ah); ah->imask |= ATH9K_INT_GENTIMER; ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); } } @@ -163,6 +164,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) ath9k_hw_disable_interrupts(ah); ah->imask &= ~ATH9K_INT_GENTIMER; ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); } } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b6b523a897e..c3af61e38bd 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -929,9 +929,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); } - if (ints & ATH9K_INT_GLOBAL) - ath9k_hw_enable_interrupts(ah); - return; } EXPORT_SYMBOL(ath9k_hw_set_interrupts); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b602447b0a8..3050d83673b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -294,6 +294,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) @@ -910,6 +911,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) /* Re-Enable interrupts */ ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); /* Enable LED */ ath9k_hw_cfg_output(ah, ah->led_pin, @@ -1016,6 +1018,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_set_beacon(sc); /* restart beacons */ ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); if (retry_tx) { int i; @@ -1130,6 +1133,7 @@ static int ath9k_start(struct ieee80211_hw *hw) /* Disable BMISS interrupt when we're not associated */ ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); ieee80211_wake_queues(hw); -- cgit v1.2.3-70-g09d2 From e8fe7336849e469978c9bbcc435903595912c4d3 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 5 Aug 2011 18:59:41 +0530 Subject: ath9k: Use atomic reference count for interrupt ops 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 Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/beacon.c | 21 +++++---------------- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/mac.c | 13 ++++++++++++- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/ath/ath9k/recv.c | 1 - 7 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 64dd4e34c86..c03949eb37c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -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; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index f1d66abc367..086c9c816bf 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -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, @@ -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, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 138722130b6..4fbcced2828 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -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; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d99f188dfcf..db38a58e752 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -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) { diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index c3af61e38bd..0f90e1521ff 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -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); @@ -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; @@ -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; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3050d83673b..1e7fe8c0e11 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -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) @@ -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); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a551a942027..5b4f05366f8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -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)) { -- cgit v1.2.3-70-g09d2 From 84c87dc86eaf5c3f70d6c85fac832b277b1f71c7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 5 Aug 2011 13:10:32 +0200 Subject: ath9k: remove ->config_pci_powersave() redundant argument We always call ->config_pci_powersave() with both restore and power_off arguments equal to 0 or both equal to 1, so merge them into one argument. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 5 ++--- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 5 ++--- drivers/net/wireless/ath/ath9k/hw-ops.h | 5 ++--- drivers/net/wireless/ath/ath9k/hw.h | 3 +-- drivers/net/wireless/ath/ath9k/main.c | 6 +++--- drivers/net/wireless/ath/ath9k/pci.c | 3 ++- 6 files changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 44d9d8d5649..70a18d14db1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -303,8 +303,7 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) * register as the other analog registers. Hence the 9 writes. */ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, - int restore, - int power_off) + bool power_off) { u8 i; u32 val; @@ -313,7 +312,7 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, return; /* Nothing to do on restore for 11N */ - if (!restore) { + if (!power_off /* !restore */) { if (AR_SREV_9280_20_OR_LATER(ah)) { /* * AR9280 2.0 or later chips use SerDes values from the diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ad2bb2bf4e8..e3d58bdb521 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -516,14 +516,13 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) * register as the other analog registers. Hence the 9 writes. */ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, - int restore, - int power_off) + bool power_off) { if (ah->is_pciexpress != true || ah->aspm_enabled != true) return; /* Nothing to do on restore for 11N */ - if (!restore) { + if (!power_off /* !restore */) { /* set bit 19 to allow forcing of pcie core into L1 state */ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index cb29e887538..8c123857c9d 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -22,10 +22,9 @@ /* Hardware core and driver accessible callbacks */ static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah, - int restore, - int power_off) + bool power_off) { - ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off); + ath9k_hw_ops(ah)->config_pci_powersave(ah, power_off); } static inline void ath9k_hw_rxena(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4fbcced2828..2ea10f31718 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -606,8 +606,7 @@ struct ath_hw_private_ops { */ struct ath_hw_ops { void (*config_pci_powersave)(struct ath_hw *ah, - int restore, - int power_off); + bool power_off); void (*rx_enable)(struct ath_hw *ah); void (*set_desc_link)(void *ds, u32 link); bool (*calibrate)(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1e7fe8c0e11..e40873215fc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -888,7 +888,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) spin_lock_bh(&sc->sc_pcu_lock); atomic_set(&ah->intr_ref_cnt, -1); - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_configpcipowersave(ah, false); if (!ah->curchan) ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); @@ -969,7 +969,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_phy_disable(ah); - ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_hw_configpcipowersave(ah, true); spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); @@ -1069,7 +1069,7 @@ static int ath9k_start(struct ieee80211_hw *hw) init_channel = ath9k_cmn_get_curchannel(hw, ah); /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_configpcipowersave(ah, false); /* * The basic interface to setting the hardware in a good diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 5685cf11cfe..65cf728fa11 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -35,6 +35,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { 0 } }; + /* return bus cachesize in 4B word units */ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { @@ -137,7 +138,7 @@ static void ath_pci_aspm_init(struct ath_common *common) if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { ah->aspm_enabled = true; /* Initialize PCIe PM and SERDES registers. */ - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_configpcipowersave(ah, false); } } -- cgit v1.2.3-70-g09d2 From 69ce674bfa69c55cdf32710d811fa89738eafbef Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 5 Aug 2011 13:10:34 +0200 Subject: ath9k: do btcoex ASPM disabling at initialization time Disable ASPM in pci ->probe on upstream (device) and downstream (PCIe port) component. According to e1000e driver authors this is required. I did not find that requirement in PCIe spec, but it seems to be logical for me. This need to be fixed for CONFIG_PCIEASPM, that will be done later ... Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 8 +++---- drivers/net/wireless/ath/ath9k/hw.h | 4 ---- drivers/net/wireless/ath/ath9k/main.c | 2 -- drivers/net/wireless/ath/ath9k/pci.c | 44 ++++++++++++++++++++--------------- 4 files changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index db44e5b0c98..875faf6894a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -603,10 +603,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_mode_regs(ah); - - if (ah->is_pciexpress) - ath9k_hw_aspm_init(ah); - else + if (!ah->is_pciexpress) ath9k_hw_disablepcie(ah); if (!AR_SREV_9300_20_OR_LATER(ah)) @@ -621,6 +618,9 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (r) return r; + if (ah->is_pciexpress) + ath9k_hw_aspm_init(ah); + r = ath9k_hw_init_macaddr(ah); if (r) { ath_err(common, "Failed to initialize MAC address\n"); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2ea10f31718..ee0d9441209 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1036,10 +1036,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); -#define ATH_PCIE_CAP_LINK_CTRL 0x70 -#define ATH_PCIE_CAP_LINK_L0S 1 -#define ATH_PCIE_CAP_LINK_L1 2 - #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e40873215fc..781af25f440 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1145,8 +1145,6 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(ah); - if (common->bus_ops->bt_coex_prep) - common->bus_ops->bt_coex_prep(common); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_resume(sc); } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 65cf728fa11..daa26b5d745 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -89,23 +89,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) return true; } -/* - * Bluetooth coexistance requires disabling ASPM. - */ -static void ath_pci_bt_coex_prep(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct pci_dev *pdev = to_pci_dev(sc->dev); - u8 aspm; - - if (!pci_is_pcie(pdev)) - return; - - pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); - aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); - pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); -} - static void ath_pci_extn_synch_enable(struct ath_common *common) { struct ath_softc *sc = (struct ath_softc *) common->priv; @@ -117,6 +100,7 @@ static void ath_pci_extn_synch_enable(struct ath_common *common) pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); } +/* Need to be called after we discover btcoex capabilities */ static void ath_pci_aspm_init(struct ath_common *common) { struct ath_softc *sc = (struct ath_softc *) common->priv; @@ -126,10 +110,33 @@ static void ath_pci_aspm_init(struct ath_common *common) int pos; u8 aspm; - if (!pci_is_pcie(pdev)) + pos = pci_pcie_cap(pdev); + if (!pos) return; parent = pdev->bus->self; + + if (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) { + /* Bluetooth coexistance requires disabling ASPM. */ + pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); + aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); + + /* + * Both upstream and downstream PCIe components should + * have the same ASPM settings. + */ + if (WARN_ON(!parent)) + return; + + pos = pci_pcie_cap(parent); + pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm); + aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm); + + return; + } + if (WARN_ON(!parent)) return; @@ -146,7 +153,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, - .bt_coex_prep = ath_pci_bt_coex_prep, .extn_synch_en = ath_pci_extn_synch_enable, .aspm_init = ath_pci_aspm_init, }; -- cgit v1.2.3-70-g09d2 From 0682c9b52bf51fbc67c4e79fcbdadcf70bd600f8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 13 Aug 2011 10:28:09 +0530 Subject: ath9k: Fix rx overrun interrupt storm Whenever RXEOL is received, both RXORN and RXEOL got cleared to avoid rx overrun interrupt storm. This was handled only for edma chips. The same scenario was also observered with AR9280, doing frequent channel type switch b/w HT20/40 with bidi traffic that is causing failure to stop rx dma. This patch clears the RXEOL & RXORN interrupts for all chips. ath: DMA failed to stop in 10 ms AR_CR=0x00000024 AR_DIAG_SW=0x42000020 DMADBG_7=0x000062c0 ath: Could not stop RX, we could be confusing the DMA engine when we start RX up ------------[ cut here ]------------ WARNING: at drivers/net/wireless/ath/ath9k/recv.c:532 ath_stoprecv+0x110/0x120 [ath9k]() Call Trace: [] warn_slowpath_common+0x7a/0xb0 [] warn_slowpath_null+0x15/0x20 [] ath_stoprecv+0x110/0x120 [ath9k] [] ath_reset+0x6a/0x200 [ath9k] Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 781af25f440..3c5db306387 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -826,11 +826,9 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & ATH9K_INT_TXURN) ath9k_hw_updatetxtriglevel(ah, true); - if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - if (status & ATH9K_INT_RXEOL) { - ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); - ath9k_hw_set_interrupts(ah, ah->imask); - } + if (status & ATH9K_INT_RXEOL) { + ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + ath9k_hw_set_interrupts(ah, ah->imask); } if (status & ATH9K_INT_MIB) { -- cgit v1.2.3-70-g09d2 From d77bf3eb5160c1356d7d7620b7d2fbe28e5e6257 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 13 Aug 2011 10:28:14 +0530 Subject: ath9k: Remove SC_OP_ENABLE_APM Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 +-- drivers/net/wireless/ath/ath9k/main.c | 4 ---- drivers/net/wireless/ath/ath9k/xmit.c | 6 +++--- 3 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c03949eb37c..4b08a3d3195 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -558,8 +558,7 @@ struct ath_ant_comb { #define SC_OP_BT_PRIORITY_DETECTED BIT(12) #define SC_OP_BT_SCAN BIT(13) #define SC_OP_ANI_RUN BIT(14) -#define SC_OP_ENABLE_APM BIT(15) -#define SC_OP_PRIM_STA_VIF BIT(16) +#define SC_OP_PRIM_STA_VIF BIT(15) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3c5db306387..2af4a1c2e2d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -565,7 +565,6 @@ set_timer: static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an; - struct ath_hw *ah = sc->sc_ah; an = (struct ath_node *)sta->drv_priv; #ifdef CONFIG_ATH9K_DEBUGFS @@ -574,9 +573,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) spin_unlock(&sc->nodes_lock); an->sta = sta; #endif - if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM) - sc->sc_flags |= SC_OP_ENABLE_APM; - if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index feef0135515..20626729795 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1584,9 +1584,9 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) { struct ath_hw *ah = sc->sc_ah; struct ath9k_channel *curchan = ah->curchan; - if ((sc->sc_flags & SC_OP_ENABLE_APM) && - (curchan->channelFlags & CHANNEL_5GHZ) && - (chainmask == 0x7) && (rate < 0x90)) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && + (curchan->channelFlags & CHANNEL_5GHZ) && + (chainmask == 0x7) && (rate < 0x90)) return 0x3; else return chainmask; -- cgit v1.2.3-70-g09d2 From e338a85e21d89574a0160fef7a89f42960cc5d7f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 13 Aug 2011 10:28:17 +0530 Subject: ath9k: Fix invalid noisefloor reading due to channel update While switching b/w HT20/40, the current channel's nf values are updated into history buffer. Since the current channel's channel type, channel flag got updated before reading nf value from hw. This channel type mismatch is causing invalid readings when hw is on ht20 but getnf tries to read on extn chains. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2af4a1c2e2d..113c1df26b3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1672,6 +1672,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel old_chan; int pos = curchan->hw_value; int old_pos = -1; unsigned long flags; @@ -1688,14 +1689,24 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) "Set channel: %d MHz type: %d\n", curchan->center_freq, conf->channel_type); - ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], - curchan, conf->channel_type); - /* update survey stats for the old channel before switching */ spin_lock_irqsave(&common->cc_lock, flags); ath_update_survey_stats(sc); spin_unlock_irqrestore(&common->cc_lock, flags); + /* + * Preserve the current channel values, before updating + * the same channel + */ + if (old_pos == pos) { + memcpy(&old_chan, &sc->sc_ah->channels[pos], + sizeof(struct ath9k_channel)); + ah->curchan = &old_chan; + } + + ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], + curchan, conf->channel_type); + /* * If the operating channel changes, change the survey in-use flags * along with it. -- cgit v1.2.3-70-g09d2 From 52c94f413fdf5011b7e54ae68e0a2cfcb1b311df Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Sat, 20 Aug 2011 17:21:42 +0530 Subject: ath9k: Add support for get_stats callback this useful for debugging and to keep track of success/failure of frames such as ACK, RTS and FCS error count in a noisy environment Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 113c1df26b3..5ac4f3f2ad6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2403,6 +2403,20 @@ skip: return sc->beacon.tx_last; } +static int ath9k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats; + + stats->dot11ACKFailureCount = mib_stats->ackrcv_bad; + stats->dot11RTSFailureCount = mib_stats->rts_bad; + stats->dot11FCSErrorCount = mib_stats->fcs_bad; + stats->dot11RTSSuccessCount = mib_stats->rts_good; + return 0; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2427,5 +2441,6 @@ struct ieee80211_ops ath9k_ops = { .set_coverage_class = ath9k_set_coverage_class, .flush = ath9k_flush, .tx_frames_pending = ath9k_tx_frames_pending, - .tx_last_beacon = ath9k_tx_last_beacon, + .tx_last_beacon = ath9k_tx_last_beacon, + .get_stats = ath9k_get_stats, }; -- cgit v1.2.3-70-g09d2 From cf3af74824b1bf2bd60eb6a0dd82b27f9e9236ac Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 27 Aug 2011 16:17:47 +0530 Subject: ath9k: Add debugfs support for mac/baseband samples This patch keep track of number of samples that includes DMA debugs registers, PCU observe, CR, channel noise, cycle conters, noisefloor history buffer and last N number of tx and rx descriptor status. These samples are grouped in table manner which dumping in debgufs. Debugfs file location: /ieee80211/phy#/ath9k/samples Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 310 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/debug.h | 47 +++++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/mac.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 2 + drivers/net/wireless/ath/ath9k/recv.c | 22 +-- 6 files changed, 369 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index da45f325be7..fbec5f7eca6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -828,6 +828,8 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq) { +#define TX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].ts\ + [sc->debug.tsidx].c) int qnum = txq->axq_qnum; TX_STAT_INC(qnum, tx_pkts_all); @@ -857,6 +859,26 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, TX_STAT_INC(qnum, data_underrun); if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(qnum, delim_underrun); + + spin_lock(&sc->debug.samp_lock); + TX_SAMP_DBG(jiffies) = jiffies; + TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0; + TX_SAMP_DBG(rssi_ctl1) = ts->ts_rssi_ctl1; + TX_SAMP_DBG(rssi_ctl2) = ts->ts_rssi_ctl2; + TX_SAMP_DBG(rssi_ext0) = ts->ts_rssi_ext0; + TX_SAMP_DBG(rssi_ext1) = ts->ts_rssi_ext1; + TX_SAMP_DBG(rssi_ext2) = ts->ts_rssi_ext2; + TX_SAMP_DBG(rateindex) = ts->ts_rateindex; + TX_SAMP_DBG(isok) = !!(ts->ts_status & ATH9K_TXERR_MASK); + TX_SAMP_DBG(rts_fail_cnt) = ts->ts_shortretry; + TX_SAMP_DBG(data_fail_cnt) = ts->ts_longretry; + TX_SAMP_DBG(rssi) = ts->ts_rssi; + TX_SAMP_DBG(tid) = ts->tid; + TX_SAMP_DBG(qid) = ts->qid; + sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock(&sc->debug.samp_lock); + +#undef TX_SAMP_DBG } static const struct file_operations fops_xmit = { @@ -995,6 +1017,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ +#define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ + [sc->debug.rsidx].c) u32 phyerr; @@ -1030,8 +1054,25 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; + spin_lock(&sc->debug.samp_lock); + RX_SAMP_DBG(jiffies) = jiffies; + RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; + RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1; + RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2; + RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0; + RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1; + RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2; + RX_SAMP_DBG(antenna) = rs->rs_antenna; + RX_SAMP_DBG(rssi) = rs->rs_rssi; + RX_SAMP_DBG(rate) = rs->rs_rate; + RX_SAMP_DBG(is_mybeacon) = rs->is_mybeacon; + + sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock(&sc->debug.samp_lock); + #undef RX_STAT_INC #undef RX_PHY_ERR_INC +#undef RX_SAMP_DBG } static const struct file_operations fops_recv = { @@ -1272,6 +1313,269 @@ static const struct file_operations fops_modal_eeprom = { .llseek = default_llseek, }; +void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +#define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + unsigned long flags; + int i; + + ath9k_ps_wakeup(sc); + + spin_lock_irqsave(&common->cc_lock, flags); + ath_hw_cycle_counters_update(common); + spin_unlock_irqrestore(&common->cc_lock, flags); + + spin_lock_bh(&sc->debug.samp_lock); + + ATH_SAMP_DBG(cc.cycles) = common->cc_ani.cycles; + ATH_SAMP_DBG(cc.rx_busy) = common->cc_ani.rx_busy; + ATH_SAMP_DBG(cc.rx_frame) = common->cc_ani.rx_frame; + ATH_SAMP_DBG(cc.tx_frame) = common->cc_ani.tx_frame; + ATH_SAMP_DBG(noise) = ah->noise; + + REG_WRITE_D(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + ATH_SAMP_DBG(dma_dbg_reg_vals[i]) = REG_READ_D(ah, + AR_DMADBG_0 + (i * sizeof(u32))); + + ATH_SAMP_DBG(pcu_obs) = REG_READ_D(ah, AR_OBS_BUS_1); + ATH_SAMP_DBG(pcu_cr) = REG_READ_D(ah, AR_CR); + + memcpy(ATH_SAMP_DBG(nfCalHist), sc->caldata.nfCalHist, + sizeof(ATH_SAMP_DBG(nfCalHist))); + + sc->debug.sampidx = (sc->debug.sampidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock_bh(&sc->debug.samp_lock); + ath9k_ps_restore(sc); + +#undef ATH_SAMP_DBG +} + +static int open_file_bb_mac_samps(struct inode *inode, struct file *file) +{ +#define ATH_SAMP_DBG(c) bb_mac_samp[sampidx].c + struct ath_softc *sc = inode->i_private; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; + struct ath_dbg_bb_mac_samp *bb_mac_samp; + struct ath9k_nfcal_hist *h; + int i, j, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase, *dcuBase, size = 30000, len = 0; + u32 sampidx = 0; + u8 *buf; + u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; + u8 nread; + + buf = vmalloc(size); + if (!buf) + return -ENOMEM; + bb_mac_samp = vmalloc(sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); + if (!bb_mac_samp) { + vfree(buf); + return -ENOMEM; + } + + spin_lock_bh(&sc->debug.samp_lock); + memcpy(bb_mac_samp, sc->debug.bb_mac_samp, + sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); + spin_unlock_bh(&sc->debug.samp_lock); + + len += snprintf(buf + len, size - len, + "Raw DMA Debug Dump:\n"); + len += snprintf(buf + len, size - len, "Sample |\t"); + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + len += snprintf(buf + len, size - len, " DMA Reg%d |\t", i); + len += snprintf(buf + len, size - len, "\n"); + + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + len += snprintf(buf + len, size - len, "%d\t", sampidx); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + len += snprintf(buf + len, size - len, " %08x\t", + ATH_SAMP_DBG(dma_dbg_reg_vals[i])); + len += snprintf(buf + len, size - len, "\n"); + } + len += snprintf(buf + len, size - len, "\n"); + + len += snprintf(buf + len, size - len, + "Sample Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); + dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, + qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + if (!sc->debug.stats.txstats[i].queued) + continue; + + len += snprintf(buf + len, size - len, + "%4d %7d %2x %1x %2x %2x\n", + sampidx, i, + (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> + (qcuOffset + 3), + ATH_SAMP_DBG(dma_dbg_reg_vals[2]) & + (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + len += snprintf(buf + len, size - len, "\n"); + } + len += snprintf(buf + len, size - len, + "samp qcu_sh qcu_fh qcu_comp dcu_comp dcu_arb dcu_fp " + "ch_idle_dur ch_idle_dur_val txfifo_val0 txfifo_val1 " + "txfifo_dcu0 txfifo_dcu1 pcu_obs AR_CR\n"); + + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); + dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); + + len += snprintf(buf + len, size - len, "%4d %5x %5x ", sampidx, + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x003c0000) >> 18, + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x03c00000) >> 22); + len += snprintf(buf + len, size - len, "%7x %8x ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x1c000000) >> 26, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x3)); + len += snprintf(buf + len, size - len, "%7x %7x ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x06000000) >> 25, + (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x38000000) >> 27); + len += snprintf(buf + len, size - len, "%7d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x000003fc) >> 2, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000400) >> 10); + len += snprintf(buf + len, size - len, "%12d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000800) >> 11, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00001000) >> 12); + len += snprintf(buf + len, size - len, "%12d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x0001e000) >> 13, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x001e0000) >> 17); + len += snprintf(buf + len, size - len, "0x%07x 0x%07x\n", + ATH_SAMP_DBG(pcu_obs), ATH_SAMP_DBG(pcu_cr)); + } + + len += snprintf(buf + len, size - len, + "Sample ChNoise Chain privNF #Reading Readings\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + h = ATH_SAMP_DBG(nfCalHist); + if (!ATH_SAMP_DBG(noise)) + continue; + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (!(chainmask & (1 << i)) || + ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) + continue; + + nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - + h[i].invalidNFcount; + len += snprintf(buf + len, size - len, + "%4d %5d %4d\t %d\t %d\t", + sampidx, ATH_SAMP_DBG(noise), + i, h[i].privNF, nread); + for (j = 0; j < nread; j++) + len += snprintf(buf + len, size - len, + " %d", h[i].nfCalBuffer[j]); + len += snprintf(buf + len, size - len, "\n"); + } + } + len += snprintf(buf + len, size - len, "\nCycle counters:\n" + "Sample Total Rxbusy Rxframes Txframes\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + if (!ATH_SAMP_DBG(cc.cycles)) + continue; + len += snprintf(buf + len, size - len, + "%4d %08x %08x %08x %08x\n", + sampidx, ATH_SAMP_DBG(cc.cycles), + ATH_SAMP_DBG(cc.rx_busy), + ATH_SAMP_DBG(cc.rx_frame), + ATH_SAMP_DBG(cc.tx_frame)); + } + + len += snprintf(buf + len, size - len, "Tx status Dump :\n"); + len += snprintf(buf + len, size - len, + "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb " + "isok rts_fail data_fail rate tid qid tx_before(ms)\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { + if (!ATH_SAMP_DBG(ts[i].jiffies)) + continue; + len += snprintf(buf + len, size - len, "%4d \t" + "%8d %4d %4d %4d %4d %4d %4d %4d %4d " + "%4d %4d %2d %2d %d\n", + sampidx, + ATH_SAMP_DBG(ts[i].rssi_ctl0), + ATH_SAMP_DBG(ts[i].rssi_ctl1), + ATH_SAMP_DBG(ts[i].rssi_ctl2), + ATH_SAMP_DBG(ts[i].rssi_ext0), + ATH_SAMP_DBG(ts[i].rssi_ext1), + ATH_SAMP_DBG(ts[i].rssi_ext2), + ATH_SAMP_DBG(ts[i].rssi), + ATH_SAMP_DBG(ts[i].isok), + ATH_SAMP_DBG(ts[i].rts_fail_cnt), + ATH_SAMP_DBG(ts[i].data_fail_cnt), + ATH_SAMP_DBG(ts[i].rateindex), + ATH_SAMP_DBG(ts[i].tid), + ATH_SAMP_DBG(ts[i].qid), + jiffies_to_msecs(jiffies - + ATH_SAMP_DBG(ts[i].jiffies))); + } + } + + len += snprintf(buf + len, size - len, "Rx status Dump :\n"); + len += snprintf(buf + len, size - len, "Sample rssi:- ctl0 ctl1 ctl2 " + "ext0 ext1 ext2 comb beacon ant rate rx_before(ms)\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { + if (!ATH_SAMP_DBG(rs[i].jiffies)) + continue; + len += snprintf(buf + len, size - len, "%4d \t" + "%8d %4d %4d %4d %4d %4d %4d %s %4d %02x %d\n", + sampidx, + ATH_SAMP_DBG(rs[i].rssi_ctl0), + ATH_SAMP_DBG(rs[i].rssi_ctl1), + ATH_SAMP_DBG(rs[i].rssi_ctl2), + ATH_SAMP_DBG(rs[i].rssi_ext0), + ATH_SAMP_DBG(rs[i].rssi_ext1), + ATH_SAMP_DBG(rs[i].rssi_ext2), + ATH_SAMP_DBG(rs[i].rssi), + ATH_SAMP_DBG(rs[i].is_mybeacon) ? + "True" : "False", + ATH_SAMP_DBG(rs[i].antenna), + ATH_SAMP_DBG(rs[i].rate), + jiffies_to_msecs(jiffies - + ATH_SAMP_DBG(rs[i].jiffies))); + } + } + + vfree(bb_mac_samp); + file->private_data = buf; + + return 0; +#undef ATH_SAMP_DBG +} + +static const struct file_operations fops_samps = { + .open = open_file_bb_mac_samps, + .read = ath9k_debugfs_read_buf, + .release = ath9k_debugfs_release_buf, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1321,6 +1625,8 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_base_eeprom); debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_modal_eeprom); + debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_samps); debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); @@ -1329,5 +1635,9 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); sc->debug.regidx = 0; + memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp)); + sc->debug.sampidx = 0; + sc->debug.tsidx = 0; + sc->debug.rsidx = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 4a04510e111..95f85bdc8db 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -177,14 +177,57 @@ struct ath_stats { struct ath_rx_stats rxstats; }; +#define ATH_DBG_MAX_SAMPLES 10 +struct ath_dbg_bb_mac_samp { + u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS]; + u32 pcu_obs, pcu_cr, noise; + struct { + u64 jiffies; + int8_t rssi_ctl0; + int8_t rssi_ctl1; + int8_t rssi_ctl2; + int8_t rssi_ext0; + int8_t rssi_ext1; + int8_t rssi_ext2; + int8_t rssi; + bool isok; + u8 rts_fail_cnt; + u8 data_fail_cnt; + u8 rateindex; + u8 qid; + u8 tid; + } ts[ATH_DBG_MAX_SAMPLES]; + struct { + u64 jiffies; + int8_t rssi_ctl0; + int8_t rssi_ctl1; + int8_t rssi_ctl2; + int8_t rssi_ext0; + int8_t rssi_ext1; + int8_t rssi_ext2; + int8_t rssi; + bool is_mybeacon; + u8 antenna; + u8 rate; + } rs[ATH_DBG_MAX_SAMPLES]; + struct ath_cycle_counters cc; + struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; +}; + struct ath9k_debug { struct dentry *debugfs_phy; u32 regidx; struct ath_stats stats; + spinlock_t samp_lock; + struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES]; + u8 sampidx; + u8 tsidx; + u8 rsidx; }; int ath9k_init_debug(struct ath_hw *ah); +void ath9k_debug_samp_bb_mac(struct ath_softc *sc); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq); @@ -197,6 +240,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) return 0; } +static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +} + static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d7761d1fc5b..dd71a5f7751 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -572,6 +572,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, mutex_init(&sc->mutex); #ifdef CONFIG_ATH9K_DEBUGFS spin_lock_init(&sc->nodes_lock); + spin_lock_init(&sc->debug.samp_lock); INIT_LIST_HEAD(&sc->nodes); #endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 153859ccc2a..2c43e13da00 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -146,6 +146,7 @@ struct ath_rx_status { u8 rs_moreaggr; u8 rs_num_delims; u8 rs_flags; + bool is_mybeacon; u32 evm0; u32 evm1; u32 evm2; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5ac4f3f2ad6..7b7864dfab7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -546,6 +546,7 @@ set_timer: * The interval must be the shortest necessary to satisfy ANI, * short calibration and long calibration. */ + ath9k_debug_samp_bb_mac(sc); cal_interval = ATH_LONG_CALINTERVAL; if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, @@ -978,6 +979,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->hw_busy_count = 0; + ath9k_debug_samp_bb_mac(sc); /* Stop ANI */ del_timer_sync(&common->ani.timer); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 800e9ee7e03..9c7f905f387 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -952,23 +952,12 @@ static void ath9k_process_rssi(struct ath_common *common, struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; - __le16 fc; - if ((ah->opmode != NL80211_IFTYPE_STATION) && - (ah->opmode != NL80211_IFTYPE_ADHOC)) + if (!rx_stats->is_mybeacon || + ((ah->opmode != NL80211_IFTYPE_STATION) && + (ah->opmode != NL80211_IFTYPE_ADHOC))) return; - fc = hdr->frame_control; - if (!ieee80211_is_beacon(fc) || - compare_ether_addr(hdr->addr3, common->curbssid)) { - /* TODO: This doesn't work well if you have stations - * associated to two different APs because curbssid - * is just the last AP that any of the stations associated - * with. - */ - return; - } - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); @@ -1838,6 +1827,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); + if (ieee80211_is_beacon(hdr->frame_control) && + !compare_ether_addr(hdr->addr3, common->curbssid)) + rs.is_mybeacon = true; + else + rs.is_mybeacon = false; ath_debug_stat_rx(sc, &rs); -- cgit v1.2.3-70-g09d2 From 82b2d334314c387ebd857b88a3d889c9a2cfec4a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 3 Sep 2011 01:40:23 +0200 Subject: ath9k: eliminate common->{rx,tx}_chainmask we already have ah->{rx,tx}chainmask for the same purpose Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 3 --- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 4 ++-- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/debug.c | 20 ++++++++++---------- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 7 ++----- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 +-- drivers/net/wireless/ath/ath9k/hw.c | 5 ++--- drivers/net/wireless/ath/ath9k/init.c | 9 ++------- drivers/net/wireless/ath/ath9k/main.c | 7 +++---- drivers/net/wireless/ath/ath9k/xmit.c | 8 ++++---- 10 files changed, 27 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 9891fb605a0..4ed7f248a57 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -140,9 +140,6 @@ struct ath_common { u8 curbssid[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; - u8 tx_chainmask; - u8 rx_chainmask; - u32 rx_bufsize; u32 keymax; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index f80d1d63398..bb2214f425b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -113,7 +113,7 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah) if (delta > scale) return -1; - switch (get_streams(common->tx_chainmask)) { + switch (get_streams(ah->txchainmask)) { case 1: delta = 6; break; @@ -126,7 +126,7 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah) default: delta = 0; ath_dbg(common, ATH_DBG_CALIBRATE, - "Invalid tx-chainmask: %u\n", common->tx_chainmask); + "Invalid tx-chainmask: %u\n", ah->txchainmask); } power += delta; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 086c9c816bf..0c757c9f978 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -107,7 +107,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, series[0].Tries = 1; series[0].Rate = rate; series[0].ChSel = ath_txchainmask_reduction(sc, - common->tx_chainmask, series[0].Rate); + ah->txchainmask, series[0].Rate); series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, series, 4, 0); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 727e8de22fd..19ef559ac78 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -95,11 +95,11 @@ static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; char buf[32]; unsigned int len; - len = sprintf(buf, "0x%08x\n", common->tx_chainmask); + len = sprintf(buf, "0x%08x\n", ah->txchainmask); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -107,7 +107,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; unsigned long mask; char buf[32]; ssize_t len; @@ -120,8 +120,8 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use if (strict_strtoul(buf, 0, &mask)) return -EINVAL; - common->tx_chainmask = mask; - sc->sc_ah->caps.tx_chainmask = mask; + ah->txchainmask = mask; + ah->caps.tx_chainmask = mask; return count; } @@ -138,11 +138,11 @@ static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; char buf[32]; unsigned int len; - len = sprintf(buf, "0x%08x\n", common->rx_chainmask); + len = sprintf(buf, "0x%08x\n", ah->rxchainmask); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -150,7 +150,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; unsigned long mask; char buf[32]; ssize_t len; @@ -163,8 +163,8 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use if (strict_strtoul(buf, 0, &mask)) return -EINVAL; - common->rx_chainmask = mask; - sc->sc_ah->caps.rx_chainmask = mask; + ah->rxchainmask = mask; + ah->caps.rx_chainmask = mask; return count; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 9cf42f6973a..966661c9e58 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -509,8 +509,8 @@ static void setup_ht_cap(struct ath9k_htc_priv *priv, memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); /* ath9k_htc supports only 1 or 2 stream devices */ - tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2); - rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2); + tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); + rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); ath_dbg(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", @@ -601,9 +601,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - common->tx_chainmask = priv->ah->caps.tx_chainmask; - common->rx_chainmask = priv->ah->caps.rx_chainmask; - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); priv->ah->opmode = NL80211_IFTYPE_STATION; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index b9de1511add..495fdf680a6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -826,8 +826,7 @@ void ath9k_htc_ani_work(struct work_struct *work) if (longcal || shortcal) common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - common->rx_chainmask, - longcal); + ah->rxchainmask, longcal); ath9k_htc_ps_restore(priv); } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 47d10a4463f..f2065fce4ec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1479,9 +1479,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u64 tsf = 0; int i, r; - ah->txchainmask = common->tx_chainmask; - ah->rxchainmask = common->rx_chainmask; - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; @@ -2095,6 +2092,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask); pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask); + ah->txchainmask = pCap->tx_chainmask; + ah->rxchainmask = pCap->rx_chainmask; ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index dd71a5f7751..50da6421728 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -270,8 +270,8 @@ static void setup_ht_cap(struct ath_softc *sc, /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams); - rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams); + tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); + rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); ath_dbg(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", @@ -506,9 +506,6 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->sc_flags |= SC_OP_RXAGGR; } - common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; - common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; - ath9k_hw_set_diversity(sc->sc_ah, true); sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); @@ -646,10 +643,8 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) static void ath9k_init_txpower_limits(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_channel *curchan = ah->curchan; - ah->txchainmask = common->tx_chainmask; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7b7864dfab7..e944eadd677 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -318,7 +318,6 @@ static void ath_paprd_activate(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_cal_data *caldata = ah->caldata; - struct ath_common *common = ath9k_hw_common(ah); int chain; if (!caldata || !caldata->paprd_done) @@ -327,7 +326,7 @@ static void ath_paprd_activate(struct ath_softc *sc) ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(common->tx_chainmask & BIT(chain))) + if (!(ah->txchainmask & BIT(chain))) continue; ar9003_paprd_populate_single_table(ah, caldata, chain); @@ -414,7 +413,7 @@ void ath_paprd_calibrate(struct work_struct *work) memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(common->tx_chainmask & BIT(chain))) + if (!(ah->txchainmask & BIT(chain))) continue; chain_ok = 0; @@ -535,7 +534,7 @@ void ath_ani_calibrate(unsigned long data) if (longcal || shortcal) { common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - common->rx_chainmask, longcal); + ah->rxchainmask, longcal); } ath9k_ps_restore(sc); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 29bcc55a6f9..0fb8fb57b5c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1634,7 +1634,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; struct ath9k_11n_rate_series series[4]; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; @@ -1694,7 +1694,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) /* MCS rates */ series[i].Rate = rix | 0x80; series[i].ChSel = ath_txchainmask_reduction(sc, - common->tx_chainmask, series[i].Rate); + ah->txchainmask, series[i].Rate); series[i].PktDuration = ath_pkt_duration(sc, rix, len, is_40, is_sgi, is_sp); if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) @@ -1719,10 +1719,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) } if (bf->bf_state.bfs_paprd) - series[i].ChSel = common->tx_chainmask; + series[i].ChSel = ah->txchainmask; else series[i].ChSel = ath_txchainmask_reduction(sc, - common->tx_chainmask, series[i].Rate); + ah->txchainmask, series[i].Rate); series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, phy, rate->bitrate * 100, len, rix, is_sp); -- cgit v1.2.3-70-g09d2 From e8cfe9f8c488f5b345ab557148c7af57af4fbe25 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 3 Sep 2011 01:40:24 +0200 Subject: ath9k: move a few functions around Helps with making ath_reset static in the next commit Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 137 +++++++++++++++++----------------- 1 file changed, 69 insertions(+), 68 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e944eadd677..9ff73e007d3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -596,74 +596,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ath_tx_node_cleanup(sc, an); } -void ath_hw_check(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - unsigned long flags; - int busy; - - ath9k_ps_wakeup(sc); - if (ath9k_hw_check_alive(sc->sc_ah)) - goto out; - - spin_lock_irqsave(&common->cc_lock, flags); - busy = ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - - ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " - "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); - if (busy >= 99) { - if (++sc->hw_busy_count >= 3) { - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); - } - } else if (busy >= 0) - sc->hw_busy_count = 0; - -out: - ath9k_ps_restore(sc); -} - -static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) -{ - static int count; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - if (pll_sqsum >= 0x40000) { - count++; - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - ath_dbg(common, ATH_DBG_RESET, - "Possible RX hang, resetting"); - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); - count = 0; - } - } else - count = 0; -} - -void ath_hw_pll_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - hw_pll_work.work); - u32 pll_sqsum; - - if (AR_SREV_9485(sc->sc_ah)) { - - ath9k_ps_wakeup(sc); - pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); - ath9k_ps_restore(sc); - - ath_hw_pll_rx_hang_check(sc, pll_sqsum); - - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); - } -} - void ath9k_tasklet(unsigned long data) { @@ -1037,6 +969,75 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } +void ath_hw_check(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long flags; + int busy; + + ath9k_ps_wakeup(sc); + if (ath9k_hw_check_alive(sc->sc_ah)) + goto out; + + spin_lock_irqsave(&common->cc_lock, flags); + busy = ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + + ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " + "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); + if (busy >= 99) { + if (++sc->hw_busy_count >= 3) { + spin_lock_bh(&sc->sc_pcu_lock); + ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); + } + + } else if (busy >= 0) + sc->hw_busy_count = 0; + +out: + ath9k_ps_restore(sc); +} + +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) +{ + static int count; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (pll_sqsum >= 0x40000) { + count++; + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_dbg(common, ATH_DBG_RESET, + "Possible RX hang, resetting"); + spin_lock_bh(&sc->sc_pcu_lock); + ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); + count = 0; + } + } else + count = 0; +} + +void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + u32 pll_sqsum; + + if (AR_SREV_9485(sc->sc_ah)) { + + ath9k_ps_wakeup(sc); + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); + ath9k_ps_restore(sc); + + ath_hw_pll_rx_hang_check(sc, pll_sqsum); + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } +} + /**********************/ /* mac80211 callbacks */ /**********************/ -- cgit v1.2.3-70-g09d2 From 236de5149b9cbec3e76aef00a4663a8de7feeebe Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 3 Sep 2011 01:40:25 +0200 Subject: ath9k: always call ath_reset from workqueue context This makes it much easier to add further rework to avoid race conditions between reset and other work items. Move other functions to make ath_reset static. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/beacon.c | 4 +--- drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 17 +++++++++++++---- drivers/net/wireless/ath/ath9k/xmit.c | 14 +++++++++----- 5 files changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5d9a9aabe47..b2992d4097c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -425,6 +425,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); #define ATH_PAPRD_TIMEOUT 100 /* msecs */ +void ath_reset_work(struct work_struct *work); void ath_hw_check(struct work_struct *work); void ath_hw_pll_work(struct work_struct *work); void ath_paprd_calibrate(struct work_struct *work); @@ -604,6 +605,7 @@ struct ath_softc { struct mutex mutex; struct work_struct paprd_work; struct work_struct hw_check_work; + struct work_struct hw_reset_work; struct completion paprd_complete; unsigned int hw_busy_count; @@ -650,7 +652,6 @@ struct ath_softc { }; void ath9k_tasklet(unsigned long data); -int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_cabq_update(struct ath_softc *); static inline void ath_read_cachesize(struct ath_common *common, int *csz) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0c757c9f978..22e8e258011 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -386,9 +386,7 @@ void ath_beacon_tasklet(unsigned long data) ath_dbg(common, ATH_DBG_BSTUCK, "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; - spin_lock(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock(&sc->sc_pcu_lock); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } return; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 50da6421728..be302fbdc3d 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -777,6 +777,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, goto error_world; } + INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9ff73e007d3..9a6db2964b1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -236,6 +236,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, del_timer_sync(&common->ani.timer); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); + cancel_work_sync(&sc->hw_reset_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->hw_pll_work); @@ -608,9 +609,7 @@ void ath9k_tasklet(unsigned long data) if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { - spin_lock(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock(&sc->sc_pcu_lock); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); return; } @@ -901,7 +900,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_ps_restore(sc); } -int ath_reset(struct ath_softc *sc, bool retry_tx) +static int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -969,6 +968,15 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } +void ath_reset_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); + + spin_lock_bh(&sc->sc_pcu_lock); + ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); +} + void ath_hw_check(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); @@ -1230,6 +1238,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&sc->hw_pll_work); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); + cancel_work_sync(&sc->hw_reset_work); if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0fb8fb57b5c..cb37047e71d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -582,7 +582,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); if (needreset) - ath_reset(sc, false); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } static bool ath_lookup_legacy(struct ath_buf *bf) @@ -1333,7 +1333,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) struct ath_atx_ac *ac, *ac_tmp, *last_ac; struct ath_atx_tid *tid, *last_tid; - if (list_empty(&txq->axq_acq) || + if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) || txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) return; @@ -2148,6 +2148,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_lock_bh(&txq->axq_lock); for (;;) { + if (work_pending(&sc->hw_reset_work)) + break; + if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; if (sc->sc_flags & SC_OP_TXAGGR) @@ -2235,9 +2238,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, @@ -2270,6 +2271,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) int status; for (;;) { + if (work_pending(&sc->hw_reset_work)) + break; + status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); if (status == -EINPROGRESS) break; -- cgit v1.2.3-70-g09d2 From 9adcf440dcc886a950a6049f928ab679912d99f4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 3 Sep 2011 01:40:26 +0200 Subject: ath9k: merge reset related functions reduces unnecessary code duplication. Also takes the sc_pcu_lock within ath_reset instead of callsites, which makes it possible to always cancel all queued work items before the reset, possibly fixing a few race conditions (work items vs reset) along with it. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 303 ++++++++++++++-------------------- 1 file changed, 127 insertions(+), 176 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9a6db2964b1..19c78be3dc4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -212,84 +212,58 @@ static int ath_update_survey_stats(struct ath_softc *sc) return ret; } -/* - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff. -*/ -static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *hchan) +static void __ath_cancel_work(struct ath_softc *sc) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_conf *conf = &common->hw->conf; - bool fastcc = true, stopped; - struct ieee80211_channel *channel = hw->conf.channel; - struct ath9k_hw_cal_data *caldata = NULL; - int r; - - if (sc->sc_flags & SC_OP_INVALID) - return -EIO; - - sc->hw_busy_count = 0; - - del_timer_sync(&common->ani.timer); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); - cancel_work_sync(&sc->hw_reset_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->hw_pll_work); +} - ath9k_ps_wakeup(sc); +static void ath_cancel_work(struct ath_softc *sc) +{ + __ath_cancel_work(sc); + cancel_work_sync(&sc->hw_reset_work); +} - spin_lock_bh(&sc->sc_pcu_lock); +static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + bool ret; - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_disable_interrupts(ah); - stopped = ath_drain_all_txq(sc, false); + ieee80211_stop_queues(sc->hw); - if (!ath_stoprecv(sc)) - stopped = false; + sc->hw_busy_count = 0; + del_timer_sync(&common->ani.timer); - if (!ath9k_hw_check_alive(ah)) - stopped = false; + ath9k_debug_samp_bb_mac(sc); + ath9k_hw_disable_interrupts(ah); - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ + ret = ath_drain_all_txq(sc, retry_tx); - if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL)) - fastcc = false; + if (!ath_stoprecv(sc)) + ret = false; - if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) - caldata = &sc->caldata; + if (!flush) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_rx_tasklet(sc, 0, true); + ath_rx_tasklet(sc, 0, false); + } else { + ath_flushrecv(sc); + } - ath_dbg(common, ATH_DBG_CONFIG, - "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n", - sc->sc_ah->curchan->channel, - channel->center_freq, conf_is_ht40(conf), - fastcc); + return ret; +} - r = ath9k_hw_reset(ah, hchan, caldata, fastcc); - if (r) { - ath_err(common, - "Unable to reset channel (%u MHz), reset status %d\n", - channel->center_freq, r); - goto ps_restore; - } +static bool ath_complete_reset(struct ath_softc *sc, bool start) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); - r = -EIO; - goto ps_restore; + return false; } ath9k_cmn_update_txpow(ah, sc->curtxpow, @@ -297,21 +271,93 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath9k_hw_set_interrupts(ah, ah->imask); ath9k_hw_enable_interrupts(ah); - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) { if (sc->sc_flags & SC_OP_BEACONS) ath_set_beacon(sc); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); if (!common->disable_ani) ath_start_ani(common); } - ps_restore: - ieee80211_wake_queues(hw); + ieee80211_wake_queues(sc->hw); + + return true; +} + +static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, + bool retry_tx) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_cal_data *caldata = NULL; + bool fastcc = true; + bool flush = false; + int r; + + __ath_cancel_work(sc); + + spin_lock_bh(&sc->sc_pcu_lock); + if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) { + fastcc = false; + caldata = &sc->caldata; + } + + if (!hchan) { + fastcc = false; + flush = true; + hchan = ah->curchan; + } + + if (fastcc && !ath9k_hw_check_alive(ah)) + fastcc = false; + + if (!ath_prepare_reset(sc, retry_tx, flush)) + fastcc = false; + + ath_dbg(common, ATH_DBG_CONFIG, + "Reset to %u MHz, HT40: %d fastcc: %d\n", + hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS | + CHANNEL_HT40PLUS)), + fastcc); + + r = ath9k_hw_reset(ah, hchan, caldata, fastcc); + if (r) { + ath_err(common, + "Unable to reset channel, reset status %d\n", r); + goto out; + } + + if (!ath_complete_reset(sc, true)) + r = -EIO; + +out: spin_unlock_bh(&sc->sc_pcu_lock); + return r; +} + + +/* + * Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. +*/ +static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *hchan) +{ + int r; + + if (sc->sc_flags & SC_OP_INVALID) + return -EIO; + + ath9k_ps_wakeup(sc); + + r = ath_reset_internal(sc, hchan, false); ath9k_ps_restore(sc); + return r; } @@ -825,28 +871,13 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) channel->center_freq, r); } - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to restart recv logic\n"); - goto out; - } - if (sc->sc_flags & SC_OP_BEACONS) - ath_set_beacon(sc); /* restart beacons */ - - /* Re-Enable interrupts */ - ath9k_hw_set_interrupts(ah, ah->imask); - ath9k_hw_enable_interrupts(ah); + ath_complete_reset(sc, true); /* Enable LED */ ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, ah->led_pin, 0); - ieee80211_wake_queues(hw); - ieee80211_queue_delayed_work(hw, &sc->hw_pll_work, HZ/2); - -out: spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); @@ -859,11 +890,10 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) int r; ath9k_ps_wakeup(sc); - cancel_delayed_work_sync(&sc->hw_pll_work); - spin_lock_bh(&sc->sc_pcu_lock); + ath_cancel_work(sc); - ieee80211_stop_queues(hw); + spin_lock_bh(&sc->sc_pcu_lock); /* * Keep the LED on when the radio is disabled @@ -874,13 +904,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_cfg_gpio_input(ah, ah->led_pin); } - /* Disable interrupts */ - ath9k_hw_disable_interrupts(ah); - - ath_drain_all_txq(sc, false); /* clear pending tx frames */ - - ath_stoprecv(sc); /* turn off frame recv */ - ath_flushrecv(sc); /* flush recv queue */ + ath_prepare_reset(sc, false, true); if (!ah->curchan) ah->curchan = ath9k_cmn_get_curchannel(hw, ah); @@ -902,49 +926,11 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) static int ath_reset(struct ath_softc *sc, bool retry_tx) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_hw *hw = sc->hw; int r; - sc->hw_busy_count = 0; - - ath9k_debug_samp_bb_mac(sc); - /* Stop ANI */ - - del_timer_sync(&common->ani.timer); - ath9k_ps_wakeup(sc); - ieee80211_stop_queues(hw); - - ath9k_hw_disable_interrupts(ah); - ath_drain_all_txq(sc, retry_tx); - - ath_stoprecv(sc); - ath_flushrecv(sc); - - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); - if (r) - ath_err(common, - "Unable to reset hardware; reset status %d\n", r); - - if (ath_startrecv(sc) != 0) - ath_err(common, "Unable to start recv logic\n"); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - - if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_set_beacon(sc); /* restart beacons */ - - ath9k_hw_set_interrupts(ah, ah->imask); - ath9k_hw_enable_interrupts(ah); + r = ath_reset_internal(sc, NULL, retry_tx); if (retry_tx) { int i; @@ -957,12 +943,6 @@ static int ath_reset(struct ath_softc *sc, bool retry_tx) } } - ieee80211_wake_queues(hw); - - /* Start ANI */ - if (!common->disable_ani) - ath_start_ani(common); - ath9k_ps_restore(sc); return r; @@ -972,9 +952,7 @@ void ath_reset_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); - spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); } void ath_hw_check(struct work_struct *work) @@ -995,11 +973,8 @@ void ath_hw_check(struct work_struct *work) ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); if (busy >= 99) { - if (++sc->hw_busy_count >= 3) { - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); - } + if (++sc->hw_busy_count >= 3) + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } else if (busy >= 0) sc->hw_busy_count = 0; @@ -1019,9 +994,7 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) /* Rx is hung for more than 500ms. Reset it */ ath_dbg(common, ATH_DBG_RESET, "Possible RX hang, resetting"); - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); count = 0; } } else @@ -1092,28 +1065,6 @@ static int ath9k_start(struct ieee80211_hw *hw) goto mutex_unlock; } - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - - /* - * Setup the hardware after reset: - * The receive engine is set going. - * Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to start recv logic\n"); - r = -EIO; - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; - } - spin_unlock_bh(&sc->sc_pcu_lock); - /* Setup our intr mask. */ ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | ATH9K_INT_FATAL | @@ -1136,12 +1087,14 @@ static int ath9k_start(struct ieee80211_hw *hw) /* Disable BMISS interrupt when we're not associated */ ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(ah, ah->imask); - ath9k_hw_enable_interrupts(ah); - ieee80211_wake_queues(hw); + if (!ath_complete_reset(sc, false)) { + r = -EIO; + spin_unlock_bh(&sc->sc_pcu_lock); + goto mutex_unlock; + } - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + spin_unlock_bh(&sc->sc_pcu_lock); if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && !ah->btcoex_hw.enabled) { @@ -1234,11 +1187,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); - cancel_delayed_work_sync(&sc->tx_complete_work); - cancel_delayed_work_sync(&sc->hw_pll_work); - cancel_work_sync(&sc->paprd_work); - cancel_work_sync(&sc->hw_check_work); - cancel_work_sync(&sc->hw_reset_work); + ath_cancel_work(sc); if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); @@ -2349,9 +2298,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); drain_txq = ath_drain_all_txq(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); + if (!drain_txq) ath_reset(sc, false); - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); ieee80211_wake_queues(hw); -- cgit v1.2.3-70-g09d2 From 43c3528430bd29f5e52438cad7cf7c0c62bf4583 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 3 Sep 2011 01:40:27 +0200 Subject: ath9k: implement .get_antenna and .set_antenna On MIMO chips this can be used to enable/disable hardware chains, ensuring that the MCS information is updated accordingly. On non-MIMO chips with rx diversity (e.g. 9285), this configures the rx input antenna. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 + drivers/net/wireless/ath/ath9k/init.c | 32 +++++++++++---- drivers/net/wireless/ath/ath9k/main.c | 71 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/recv.c | 2 +- 4 files changed, 99 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b2992d4097c..0fb4a26f897 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -649,6 +649,7 @@ struct ath_softc { struct ath_descdma txsdma; struct ath_ant_comb ant_comb; + u8 ant_tx, ant_rx; }; void ath9k_tasklet(unsigned long data); @@ -669,6 +670,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); +void ath9k_reload_chainmask_settings(struct ath_softc *sc); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_uses_beacons(int type); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index be302fbdc3d..9b34c4bab93 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -653,9 +653,22 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) ah->curchan = curchan; } +void ath9k_reload_chainmask_settings(struct ath_softc *sc) +{ + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)) + return; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); +} + + void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | @@ -693,6 +706,16 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); + hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; + hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; + + /* single chain devices with rx diversity */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) + hw->wiphy->available_antennas_rx = BIT(0) | BIT(1); + + sc->ant_rx = hw->wiphy->available_antennas_rx; + sc->ant_tx = hw->wiphy->available_antennas_tx; + #ifdef CONFIG_ATH9K_RATE_CONTROL hw->rate_control_algorithm = "ath9k_rate_control"; #endif @@ -704,12 +727,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } + ath9k_reload_chainmask_settings(sc); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 19c78be3dc4..c8ac2ce61ff 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -281,6 +281,22 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath_start_ani(common); } + if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) { + struct ath_hw_antcomb_conf div_ant_conf; + u8 lna_conf; + + ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); + + if (sc->ant_rx == 1) + lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + lna_conf = ATH_ANT_DIV_COMB_LNA2; + div_ant_conf.main_lna_conf = lna_conf; + div_ant_conf.alt_lna_conf = lna_conf; + + ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); + } + ieee80211_wake_queues(sc->hw); return true; @@ -2379,6 +2395,59 @@ static int ath9k_get_stats(struct ieee80211_hw *hw, return 0; } +static u32 fill_chainmask(u32 cap, u32 new) +{ + u32 filled = 0; + int i; + + for (i = 0; cap && new; i++, cap >>= 1) { + if (!(cap & BIT(0))) + continue; + + if (new & BIT(0)) + filled |= BIT(i); + + new >>= 1; + } + + return filled; +} + +static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + + if (!rx_ant || !tx_ant) + return -EINVAL; + + sc->ant_rx = rx_ant; + sc->ant_tx = tx_ant; + + if (ah->caps.rx_chainmask == 1) + return 0; + + /* AR9100 runs into calibration issues if not all rx chains are enabled */ + if (AR_SREV_9100(ah)) + ah->rxchainmask = 0x7; + else + ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); + + ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); + ath9k_reload_chainmask_settings(sc); + + return 0; +} + +static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct ath_softc *sc = hw->priv; + + *tx_ant = sc->ant_tx; + *rx_ant = sc->ant_rx; + return 0; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2405,4 +2474,6 @@ struct ieee80211_ops ath9k_ops = { .tx_frames_pending = ath9k_tx_frames_pending, .tx_last_beacon = ath9k_tx_last_beacon, .get_stats = ath9k_get_stats, + .set_antenna = ath9k_set_antenna, + .get_antenna = ath9k_get_antenna, }; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9c7f905f387..8d3e19dfe7d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1950,7 +1950,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath_rx_ps(sc, skb); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) ath_ant_comb_scan(sc, &rs); ieee80211_rx(hw, skb); -- cgit v1.2.3-70-g09d2 From e392700741a4a5f061f3fcc9f5f2ceb0e0b0953e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 14 Sep 2011 21:23:01 +0200 Subject: ath9k: fix enabling interrupts after a hardware error interrupt The interrupt handler increases the interrupt disable refcount, so the tasklet needs to always call ath9k_hw_enable_interrupts. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c8ac2ce61ff..03b402bb9c4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -669,15 +669,15 @@ void ath9k_tasklet(unsigned long data) u32 status = sc->intrstatus; u32 rxmask; + ath9k_ps_wakeup(sc); + spin_lock(&sc->sc_pcu_lock); + if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { ieee80211_queue_work(sc->hw, &sc->hw_reset_work); - return; + goto out; } - ath9k_ps_wakeup(sc); - spin_lock(&sc->sc_pcu_lock); - /* * Only run the baseband hang check if beacons stop working in AP or * IBSS mode, because it has a high false positive rate. For station @@ -725,6 +725,7 @@ void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); +out: /* re-enable hardware interrupt */ ath9k_hw_enable_interrupts(ah); -- cgit v1.2.3-70-g09d2 From 3483288caf3d979e6b032d62f75f57893adf0d53 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 14 Sep 2011 21:23:03 +0200 Subject: ath9k: ensure that rx is not enabled during a reset During a reset, rx buffers are flushed after rx has been disabled. To avoid race conditions, rx needs to stay disabled during the reset, so avoid any calls to ath9k_hw_rxena in that case. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/ath/ath9k/recv.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 03b402bb9c4..8149511e8f7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -247,8 +247,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) if (!flush) { if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) - ath_rx_tasklet(sc, 0, true); - ath_rx_tasklet(sc, 0, false); + ath_rx_tasklet(sc, 1, true); + ath_rx_tasklet(sc, 1, false); } else { ath_flushrecv(sc); } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 8d3e19dfe7d..bcc0b222ec1 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1839,7 +1839,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. */ - if (flush) + if (sc->sc_flags & SC_OP_RXFLUSH) goto requeue_drop_frag; retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, @@ -1967,7 +1967,8 @@ requeue: } else { list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); - ath9k_hw_rxena(ah); + if (!flush) + ath9k_hw_rxena(ah); } } while (1); -- cgit v1.2.3-70-g09d2 From c6c539f023423a7a730f5759be1b3b45c2d1d1ca Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 14 Sep 2011 21:24:24 +0200 Subject: ath9k: optimize ath9k_ps_restore ath_hw_cycle_counters_update only needs to be called if the power state changes. Most of the time this does not happen, even when ps_usecount goes down to 0. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8149511e8f7..7910165cf0e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -111,24 +111,29 @@ void ath9k_ps_wakeup(struct ath_softc *sc) void ath9k_ps_restore(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + enum ath9k_power_mode mode; unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (--sc->ps_usecount != 0) goto unlock; - spin_lock(&common->cc_lock); - ath_hw_cycle_counters_update(common); - spin_unlock(&common->cc_lock); - if (sc->ps_idle) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); + mode = ATH9K_PM_FULL_SLEEP; else if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + mode = ATH9K_PM_NETWORK_SLEEP; + else + goto unlock; + + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + spin_unlock(&common->cc_lock); + + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -- cgit v1.2.3-70-g09d2 From d2c71c20789189cd01978efcbdd61231f5929eaf Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 15 Sep 2011 19:02:54 +0530 Subject: ath9k: Reset caldata on radio enable Not doing so, the caldata continues to retain older history values learned on that channel. It is always safer to start noise floor calibration from the defaults after the assoication. So this patch resets the nf history buffer when none of the STA vifs are associated. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7910165cf0e..6dcd8def553 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2021,6 +2021,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) /* Stop ANI */ sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); + memset(&sc->caldata, 0, sizeof(sc->caldata)); } } -- cgit v1.2.3-70-g09d2 From 37a41b4affa33bb237d3692bf51f1b5ebcaf29d8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 21 Sep 2011 14:06:11 +0300 Subject: mac80211: add ieee80211_vif param to tsf functions TSF can be kept per vif. Add ieee80211_vif param to set/get/reset_tsf, and move the debugfs entries to the per-vif directory. Update all the drivers that implement these callbacks. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 3 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 6 +-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 9 ++-- drivers/net/wireless/ath/ath9k/main.c | 8 ++-- drivers/net/wireless/ath/carl9170/main.c | 3 +- drivers/net/wireless/b43/main.c | 5 ++- drivers/net/wireless/iwlegacy/iwl-core.c | 3 +- drivers/net/wireless/iwlegacy/iwl-core.h | 3 +- drivers/net/wireless/rt2x00/rt2400pci.c | 5 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 3 +- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/rt2x00/rt2800lib.h | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- drivers/net/wireless/rtl818x/rtl8180/dev.c | 5 ++- drivers/net/wireless/rtl818x/rtl8187/dev.c | 2 +- drivers/net/wireless/rtlwifi/core.c | 8 ++-- drivers/net/wireless/wl12xx/main.c | 3 +- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 12 ++++-- drivers/staging/winbond/wbusb.c | 2 +- include/net/mac80211.h | 7 ++-- net/mac80211/debugfs.c | 52 ------------------------ net/mac80211/debugfs_netdev.c | 48 +++++++++++++++++++++- net/mac80211/driver-ops.h | 22 ++++++---- net/mac80211/driver-trace.h | 26 +++++++----- net/mac80211/ibss.c | 4 +- 27 files changed, 137 insertions(+), 112 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 43ebc44fc82..3b752d9fb3c 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1249,7 +1249,8 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev) return 0; } -static u64 adm8211_get_tsft(struct ieee80211_hw *dev) +static u64 adm8211_get_tsft(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct adm8211_priv *priv = dev->priv; u32 tsftl; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 0560234ec3f..bba4f6fcf7e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -602,7 +602,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, static u64 -ath5k_get_tsf(struct ieee80211_hw *hw) +ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; @@ -611,7 +611,7 @@ ath5k_get_tsf(struct ieee80211_hw *hw) static void -ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf) { struct ath5k_hw *ah = hw->priv; @@ -620,7 +620,7 @@ ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) static void -ath5k_reset_tsf(struct ieee80211_hw *hw) +ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 495fdf680a6..17dbbd9d2f5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1563,7 +1563,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } -static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) +static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; u64 tsf; @@ -1577,7 +1578,8 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { struct ath9k_htc_priv *priv = hw->priv; @@ -1588,7 +1590,8 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) mutex_unlock(&priv->mutex); } -static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ee39702da5d..fb803e20976 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2143,7 +2143,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_ps_restore(sc); } -static u64 ath9k_get_tsf(struct ieee80211_hw *hw) +static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; u64 tsf; @@ -2157,7 +2157,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void ath9k_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 tsf) { struct ath_softc *sc = hw->priv; @@ -2168,7 +2170,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) mutex_unlock(&sc->mutex); } -static void ath9k_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index af351ecd87c..8b780d6d470 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1078,7 +1078,8 @@ out: mutex_unlock(&ar->mutex); } -static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw) +static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ar9170 *ar = hw->priv; struct carl9170_tsf_rsp tsf; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 56fa3a3648c..559bcd6688e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3599,7 +3599,7 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 b43_op_get_tsf(struct ieee80211_hw *hw) +static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -3618,7 +3618,8 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void b43_op_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 35cd2537e7f..c4921911c6d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2220,7 +2220,8 @@ out: } EXPORT_SYMBOL(iwl_legacy_mac_config); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index 84da79376ef..b2df01c8f8f 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -620,7 +620,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( /* mac80211 handlers */ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw); +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index daa32fc9398..7e9272b8f01 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1239,7 +1239,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, * call, we must decrease the higher 32bits with 1 to get * to correct value. */ - tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw); + tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL); rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME); rx_high = upper_32_bits(tsf); @@ -1673,7 +1673,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index b46c3b8866f..dcc0e1fcca7 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1966,7 +1966,8 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 31c98509f7e..9688dd0a7eb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4466,7 +4466,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, } EXPORT_SYMBOL_GPL(rt2800_conf_tx); -u64 rt2800_get_tsf(struct ieee80211_hw *hw) +u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 7a2511f6785..6de128e9c61 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -199,7 +199,7 @@ void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params); -u64 rt2800_get_tsf(struct ieee80211_hw *hw); +u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 058ef4b19d1..6b6a8e2dcdd 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2940,7 +2940,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } -static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 0baeb894f09..6f51e39f559 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2279,7 +2279,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } -static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) +static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 66b29dc07cc..0082015ff66 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -669,7 +669,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev) rtl8180_free_tx_ring(dev, i); } -static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) +static u64 rtl8180_get_tsf(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct rtl8180_priv *priv = dev->priv; @@ -701,7 +702,7 @@ static void rtl8180_beacon_work(struct work_struct *work) * TODO: make hardware update beacon timestamp */ mgmt = (struct ieee80211_mgmt *)skb->data; - mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev)); + mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif)); /* TODO: use actual beacon queue */ skb_set_queue_mapping(skb, 0); diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 1e0be14d10d..f5afa155ce9 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -1277,7 +1277,7 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } -static u64 rtl8187_get_tsf(struct ieee80211_hw *dev) +static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) { struct rtl8187_priv *priv = dev->priv; diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 04c4e9eb6ee..21e40f62a8d 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -775,7 +775,7 @@ out: mutex_unlock(&rtlpriv->locks.conf_mutex); } -static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); u64 tsf; @@ -784,7 +784,8 @@ static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -794,7 +795,8 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss)); } -static void rtl_op_reset_tsf(struct ieee80211_hw *hw) +static void rtl_op_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmp = 0; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a51dd0ed6d2..7d409b0f335 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3815,7 +3815,8 @@ out: return ret; } -static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index cabfae1e70b..0a70149df3f 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1332,7 +1332,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, } } -static u64 zd_op_get_tsf(struct ieee80211_hw *hw) +static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct zd_mac *mac = zd_hw_mac(hw); return zd_chip_get_tsf(&mac->chip); diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c index d6de44e430d..315dd91800b 100644 --- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c @@ -133,7 +133,8 @@ static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw); static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw); -static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf); +static void brcms_ops_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf); static int brcms_ops_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); static void brcms_ops_sta_notify(struct ieee80211_hw *hw, @@ -142,7 +143,8 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta); static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); -static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw); +static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); static int brcms_ops_sta_remove(struct ieee80211_hw *hw, @@ -516,7 +518,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) return; } -static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void brcms_ops_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { wiphy_err(hw->wiphy, "%s: Enter\n", __func__); return; @@ -565,7 +568,8 @@ brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw) +static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { wiphy_err(hw->wiphy, "%s: Enter\n", __func__); return 0; diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 3724e1e67ec..a2e8bd452ed 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -277,7 +277,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) +static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) { printk("wbsoft_get_tsf called\n"); return 0; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c0f63fd0c52..90dfcc99b46 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2000,9 +2000,10 @@ struct ieee80211_ops { enum sta_notify_cmd, struct ieee80211_sta *sta); int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); - u64 (*get_tsf)(struct ieee80211_hw *hw); - void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); - void (*reset_tsf)(struct ieee80211_hw *hw); + u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf); + void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index c9141168fd4..883996b2f99 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -78,57 +78,6 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); -static ssize_t tsf_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - u64 tsf; - - tsf = drv_get_tsf(local); - - return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n", - (unsigned long long) tsf); -} - -static ssize_t tsf_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - unsigned long long tsf; - char buf[100]; - size_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - if (strncmp(buf, "reset", 5) == 0) { - if (local->ops->reset_tsf) { - drv_reset_tsf(local); - wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); - } - } else { - tsf = simple_strtoul(buf, NULL, 0); - if (local->ops->set_tsf) { - drv_set_tsf(local, tsf); - wiphy_info(local->hw.wiphy, - "debugfs set TSF to %#018llx\n", tsf); - - } - } - - return count; -} - -static const struct file_operations tsf_ops = { - .read = tsf_read, - .write = tsf_write, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; - static ssize_t reset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -447,7 +396,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(frequency); DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(tsf); DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); DEBUGFS_ADD(noack); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index dd046291751..9352819a986 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -21,6 +21,7 @@ #include "rate.h" #include "debugfs.h" #include "debugfs_netdev.h" +#include "driver-ops.h" static ssize_t ieee80211_if_read( struct ieee80211_sub_if_data *sdata, @@ -331,6 +332,46 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( } __IEEE80211_IF_FILE(num_buffered_multicast, NULL); +/* IBSS attributes */ +static ssize_t ieee80211_if_fmt_tsf( + const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) +{ + struct ieee80211_local *local = sdata->local; + u64 tsf; + + tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata); + + return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf); +} + +static ssize_t ieee80211_if_parse_tsf( + struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) +{ + struct ieee80211_local *local = sdata->local; + unsigned long long tsf; + int ret; + + if (strncmp(buf, "reset", 5) == 0) { + if (local->ops->reset_tsf) { + drv_reset_tsf(local, sdata); + wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); + } + } else { + ret = kstrtoull(buf, 10, &tsf); + if (ret < 0) + return -EINVAL; + if (local->ops->set_tsf) { + drv_set_tsf(local, sdata, tsf); + wiphy_info(local->hw.wiphy, + "debugfs set TSF to %#018llx\n", tsf); + } + } + + return buflen; +} +__IEEE80211_IF_FILE_W(tsf); + + /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); @@ -421,6 +462,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD_MODE(tkip_mic_test, 0200); } +static void add_ibss_files(struct ieee80211_sub_if_data *sdata) +{ + DEBUGFS_ADD_MODE(tsf, 0600); +} + static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted); @@ -515,7 +561,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata) add_sta_files(sdata); break; case NL80211_IFTYPE_ADHOC: - /* XXX */ + add_ibss_files(sdata); break; case NL80211_IFTYPE_AP: add_ap_files(sdata); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9001ff331f0..5e5d97389bc 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -427,36 +427,40 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, return ret; } -static inline u64 drv_get_tsf(struct ieee80211_local *local) +static inline u64 drv_get_tsf(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { u64 ret = -1ULL; might_sleep(); - trace_drv_get_tsf(local); + trace_drv_get_tsf(local, sdata); if (local->ops->get_tsf) - ret = local->ops->get_tsf(&local->hw); + ret = local->ops->get_tsf(&local->hw, &sdata->vif); trace_drv_return_u64(local, ret); return ret; } -static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) +static inline void drv_set_tsf(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u64 tsf) { might_sleep(); - trace_drv_set_tsf(local, tsf); + trace_drv_set_tsf(local, sdata, tsf); if (local->ops->set_tsf) - local->ops->set_tsf(&local->hw, tsf); + local->ops->set_tsf(&local->hw, &sdata->vif, tsf); trace_drv_return_void(local); } -static inline void drv_reset_tsf(struct ieee80211_local *local) +static inline void drv_reset_tsf(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { might_sleep(); - trace_drv_reset_tsf(local); + trace_drv_reset_tsf(local, sdata); if (local->ops->reset_tsf) - local->ops->reset_tsf(&local->hw); + local->ops->reset_tsf(&local->hw, &sdata->vif); trace_drv_return_void(local); } diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index f47b00dc7af..07d94ff5579 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -726,35 +726,41 @@ TRACE_EVENT(drv_conf_tx, ) ); -DEFINE_EVENT(local_only_evt, drv_get_tsf, - TP_PROTO(struct ieee80211_local *local), - TP_ARGS(local) +DEFINE_EVENT(local_sdata_evt, drv_get_tsf, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) ); TRACE_EVENT(drv_set_tsf, - TP_PROTO(struct ieee80211_local *local, u64 tsf), + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u64 tsf), - TP_ARGS(local, tsf), + TP_ARGS(local, sdata, tsf), TP_STRUCT__entry( LOCAL_ENTRY + VIF_ENTRY __field(u64, tsf) ), TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; __entry->tsf = tsf; ), TP_printk( - LOCAL_PR_FMT " tsf:%llu", - LOCAL_PR_ARG, (unsigned long long)__entry->tsf + LOCAL_PR_FMT VIF_PR_FMT " tsf:%llu", + LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf ) ); -DEFINE_EVENT(local_only_evt, drv_reset_tsf, - TP_PROTO(struct ieee80211_local *local), - TP_ARGS(local) +DEFINE_EVENT(local_sdata_evt, drv_reset_tsf, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) ); DEFINE_EVENT(local_only_evt, drv_tx_last_beacon, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 836b2752ecd..7809895df8b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -81,7 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, lockdep_assert_held(&ifibss->mtx); /* Reset own TSF to allow time synchronization work. */ - drv_reset_tsf(local); + drv_reset_tsf(local, sdata); skb = ifibss->skb; rcu_assign_pointer(ifibss->presp, NULL); @@ -382,7 +382,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, * second best option: get current TSF * (will return -1 if not supported) */ - rx_timestamp = drv_get_tsf(local); + rx_timestamp = drv_get_tsf(local, sdata); } #ifdef CONFIG_MAC80211_IBSS_DEBUG -- cgit v1.2.3-70-g09d2 From 1a8f0d39a04beb0fd61f46ed99fd05189083b409 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 22 Sep 2011 08:04:32 -0600 Subject: ath9k: fix a regression in ath9k_ps_restore After 'ath9k: optimize ath9k_ps_restore', it would only send the device to network sleep and not to full sleep anymore, potentially causing more battery drain. Reported-by: Vivek Natarajan Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fb803e20976..edaa7843bf4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -133,7 +133,7 @@ void ath9k_ps_restore(struct ath_softc *sc) ath_hw_cycle_counters_update(common); spin_unlock(&common->cc_lock); - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + ath9k_hw_setpower(sc->sc_ah, mode); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -- cgit v1.2.3-70-g09d2 From 042ec4533720122e6cb93dd9f3b6a75fe2fcff16 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Sep 2011 16:04:26 +0200 Subject: mac80211: let drivers inform it about per TID buffered frames For uAPSD implementation, it is necessary to know on which ACs frames are buffered. mac80211 obviously knows about the frames it has buffered itself, but with aggregation many drivers buffer frames. Thus, mac80211 needs to be informed about this. For now, since we don't have APSD in any form, this will unconditionally set the TIM bit for the station but later with uAPSD only some ACs might cause the TIM bit to be set. ath9k is the only driver using this API and I only modify it in the most basic way, it won't be able to implement uAPSD with this yet. But it can't do that anyway since there's no way to selectively release frames to the peer yet. Since drivers will buffer frames per TID, let them inform mac80211 on a per TID basis, mac80211 will then sort out the AC mapping itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/main.c | 3 +-- drivers/net/wireless/ath/ath9k/xmit.c | 14 +++++++------- include/net/mac80211.h | 34 ++++++++++++++++++++++++++-------- net/mac80211/sta_info.c | 8 ++++++-- 5 files changed, 42 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 94d887b65e6..1e861478318 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); -bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); +void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, + struct ath_node *an); /********/ /* VIFs */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index edaa7843bf4..0ebf7321df1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; - if (ath_tx_aggr_sleep(sc, an)) - ieee80211_sta_set_tim(sta); + ath_tx_aggr_sleep(sta, sc, an); break; case STA_NOTIFY_AWAKE: an->sleeping = false; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f5d4764888b..c2bfc57958d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, /* prepend un-acked frames to the beginning of the pending frame queue */ if (!skb_queue_empty(&bf_pending)) { if (an->sleeping) - ieee80211_sta_set_tim(sta); + ieee80211_sta_set_buffered(sta, tid->tidno, true); spin_lock_bh(&txq->axq_lock); if (clear_filter) @@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ath_tx_flush_tid(sc, txtid); } -bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) +void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, + struct ath_node *an) { struct ath_atx_tid *tid; struct ath_atx_ac *ac; struct ath_txq *txq; - bool buffered = false; + bool buffered; int tidno; for (tidno = 0, tid = &an->tid[tidno]; @@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) spin_lock_bh(&txq->axq_lock); - if (!skb_queue_empty(&tid->buf_q)) - buffered = true; + buffered = !skb_queue_empty(&tid->buf_q); tid->sched = false; list_del(&tid->list); @@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) } spin_unlock_bh(&txq->axq_lock); - } - return buffered; + ieee80211_sta_set_buffered(sta, tidno, buffered); + } } void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b5f7ada2f87..e66638e749c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2361,17 +2361,35 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, #define IEEE80211_TX_STATUS_HEADROOM 13 /** - * ieee80211_sta_set_tim - set the TIM bit for a sleeping station + * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames * @sta: &struct ieee80211_sta pointer for the sleeping station + * @tid: the TID that has buffered frames + * @buffered: indicates whether or not frames are buffered for this TID * * If a driver buffers frames for a powersave station instead of passing - * them back to mac80211 for retransmission, the station needs to be told - * to wake up using the TIM bitmap in the beacon. - * - * This function sets the station's TIM bit - it will be cleared when the - * station wakes up. - */ -void ieee80211_sta_set_tim(struct ieee80211_sta *sta); + * them back to mac80211 for retransmission, the station may still need + * to be told that there are buffered frames via the TIM bit. + * + * This function informs mac80211 whether or not there are frames that are + * buffered in the driver for a given TID; mac80211 can then use this data + * to set the TIM bit (NOTE: This may call back into the driver's set_tim + * call! Beware of the locking!) + * + * If all frames are released to the station (due to PS-poll or uAPSD) + * then the driver needs to inform mac80211 that there no longer are + * frames buffered. However, when the station wakes up mac80211 assumes + * that all buffered frames will be transmitted and clears this data, + * drivers need to make sure they inform mac80211 about all buffered + * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP). + * + * Note that technically mac80211 only needs to know this per AC, not per + * TID, but since driver buffering will inevitably happen per TID (since + * it is related to aggregation) it is easier to make mac80211 map the + * TID to the AC as required instead of keeping track in all drivers that + * use this API. + */ +void ieee80211_sta_set_buffered(struct ieee80211_sta *sta, + u8 tid, bool buffered); /** * ieee80211_tx_status - transmit status callback diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c52e58c0a97..016742d4c48 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1117,11 +1117,15 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_sta_block_awake); -void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) +void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, + u8 tid, bool buffered) { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + if (!buffered) + return; + set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); sta_info_set_tim_bit(sta); } -EXPORT_SYMBOL(ieee80211_sta_set_tim); +EXPORT_SYMBOL(ieee80211_sta_set_buffered); -- cgit v1.2.3-70-g09d2 From 8a3a3c85e44d58f5af0adac74a0b866ba89a1978 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 2 Oct 2011 10:15:52 +0200 Subject: mac80211: pass vif param to conf_tx() callback tx params should be configured per interface. add ieee80211_vif param to the conf_tx callback, and change all the drivers that use this callback. The following spatch was used: @rule1@ struct ieee80211_ops ops; identifier conf_tx_op; @@ ops.conf_tx = conf_tx_op; @rule2@ identifier rule1.conf_tx_op; identifier hw, queue, params; @@ conf_tx_op ( - struct ieee80211_hw *hw, + struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) {...} Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 ++- drivers/net/wireless/ath/ath9k/main.c | 3 ++- drivers/net/wireless/ath/carl9170/main.c | 3 ++- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43legacy/main.c | 3 ++- drivers/net/wireless/iwlegacy/iwl-core.c | 3 ++- drivers/net/wireless/iwlegacy/iwl-core.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-core.h | 3 ++- drivers/net/wireless/mac80211_hwsim.c | 3 ++- drivers/net/wireless/mwl8k.c | 5 +++-- drivers/net/wireless/p54/main.c | 3 ++- drivers/net/wireless/rt2x00/rt2400pci.c | 5 +++-- drivers/net/wireless/rt2x00/rt2800lib.c | 5 +++-- drivers/net/wireless/rt2x00/rt2800lib.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 ++- drivers/net/wireless/rt2x00/rt61pci.c | 5 +++-- drivers/net/wireless/rt2x00/rt73usb.c | 5 +++-- drivers/net/wireless/rtl818x/rtl8187/dev.c | 3 ++- drivers/net/wireless/rtlwifi/core.c | 3 ++- drivers/net/wireless/wl1251/main.c | 3 ++- drivers/net/wireless/wl12xx/main.c | 3 ++- drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 7 ++++--- include/net/mac80211.h | 3 ++- net/mac80211/driver-ops.h | 3 ++- 27 files changed, 61 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index bba4f6fcf7e..6ed4c0717e3 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -563,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw, static int -ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, +ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 17dbbd9d2f5..0b9a0e8a495 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, return ret; } -static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0ebf7321df1..98831866575 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1842,7 +1842,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } } -static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int ath9k_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 8b780d6d470..beca71073e9 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1305,7 +1305,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, return 0; } -static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int carl9170_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *param) { struct ar9170 *ar = hw->priv; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 43400fb62e1..7cf4125a162 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3559,7 +3559,8 @@ static void b43_qos_init(struct b43_wldev *dev) b43dbg(dev->wl, "QoS enabled\n"); } -static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, +static int b43_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 468d1836548..a3b72cd72c6 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2466,7 +2466,8 @@ out: } } -static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { return 0; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 8928d47432d..2bd5659310d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -1250,7 +1250,8 @@ void iwl_legacy_clear_isr_stats(struct iwl_priv *priv) memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); } -int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index b2df01c8f8f..d1271fe07d4 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -286,7 +286,8 @@ struct iwl_cfg { ***************************/ struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg); -int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fc400bb2bdf..0725603dbf1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1123,8 +1123,9 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) &statistics_cmd); } -int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) +int iwl_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e55ffad8395..db50b650756 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -236,7 +236,8 @@ struct iwl_cfg { * L i b * ***************************/ -int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 34b79fc91e3..68455a2307c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -970,7 +970,8 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, } static int mac80211_hwsim_conf_tx( - struct ieee80211_hw *hw, u16 queue, + struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { wiphy_debug(hw->wiphy, diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ea1395aafa3..995695c28d5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -4915,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, return ret; } -static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int mwl8k_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mwl8k_priv *priv = hw->priv; @@ -5462,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) goto fail; for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { - rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); + rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]); if (rc) goto fail; } diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 726a9343f51..ad9ae04d07a 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev, p54_set_groupfilter(priv); } -static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int p54_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 7e9272b8f01..3a6b40239bc 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1648,7 +1648,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1661,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, if (queue != 0) return -EINVAL; - if (rt2x00mac_conf_tx(hw, queue, params)) + if (rt2x00mac_conf_tx(hw, vif, queue, params)) return -EINVAL; /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9688dd0a7eb..3f183a15186 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4398,7 +4398,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); -int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2800_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -4414,7 +4415,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 6de128e9c61..8c3c281904f 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -197,7 +197,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, u16 *iv16); int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2800_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params); u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index cbf8eb334e9..2ec5c00235e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1299,7 +1299,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cef1c878c37..bf0acff0780 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -713,7 +713,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6b6a8e2dcdd..bf55b4a311e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2883,7 +2883,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +static int rt61pci_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2899,7 +2900,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6f51e39f559..cfb19dbb0a6 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +static int rt73usb_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2238,7 +2239,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index f5afa155ce9..24873b55b55 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -1241,7 +1241,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); } -static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int rtl8187_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rtl8187_priv *priv = dev->priv; diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 21e40f62a8d..3f0f056fae9 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -504,7 +504,8 @@ static int _rtl_get_hal_qnum(u16 queue) *for mac80211 VO=0, VI=1, BE=2, BK=3 *for rtl819x BE=0, BK=1, VI=2, VO=3 */ -static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int rtl_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *param) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index a14a48c99cd..ba3268ea81f 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -1158,7 +1158,8 @@ static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 13, .center_freq = 2472}, }; -static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int wl1251_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { enum wl1251_acx_ps_scheme ps_scheme; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7d409b0f335..e2d6edd2fcd 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3744,7 +3744,8 @@ out: mutex_unlock(&wl->mutex); } -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int wl1271_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct wl1271 *wl = hw->priv; diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c index 315dd91800b..6d71cba3a0a 100644 --- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c @@ -141,8 +141,9 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta); -static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params); +static int brcms_ops_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params); static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -556,7 +557,7 @@ brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static int -brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, +brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct brcms_info *wl = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 135e897b61c..cd108dfa195 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2152,7 +2152,8 @@ struct ieee80211_ops { struct ieee80211_sta *sta); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, struct ieee80211_sta *sta); - int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, + int (*conf_tx)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 68721d379fe..5f165d7eb2d 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -423,7 +423,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local, trace_drv_conf_tx(local, sdata, queue, params); if (local->ops->conf_tx) - ret = local->ops->conf_tx(&local->hw, queue, params); + ret = local->ops->conf_tx(&local->hw, &sdata->vif, + queue, params); trace_drv_return_int(local, ret); return ret; } -- cgit v1.2.3-70-g09d2 From 030d6294351bfb0e29e2814bb8f6e6c2e25ffb54 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Oct 2011 02:28:13 +0200 Subject: ath9k: keep track of what's triggering hardware resets Export how many times each of the reset triggers has fired through debugfs. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 19 ++++++++++++++++--- drivers/net/wireless/ath/ath9k/debug.h | 13 +++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 15 ++++++++++++++- drivers/net/wireless/ath/ath9k/xmit.c | 5 ++++- 4 files changed, 47 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a5329c98f9e..327aa28f603 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -523,9 +523,22 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, if (tmp & ATH9K_RX_FILTER_PHYRADAR) len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n"); - else - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); + + len += snprintf(buf + len, sizeof(buf) - len, + "\n\nReset causes:\n" + " baseband hang: %d\n" + " baseband watchdog: %d\n" + " fatal hardware error interrupt: %d\n" + " tx hardware error: %d\n" + " tx path hang: %d\n" + " pll rx hang: %d\n", + sc->debug.stats.reset[RESET_TYPE_BB_HANG], + sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG], + sc->debug.stats.reset[RESET_TYPE_FATAL_INT], + sc->debug.stats.reset[RESET_TYPE_TX_ERROR], + sc->debug.stats.reset[RESET_TYPE_TX_HANG], + sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index b93e88bd8c5..356352ac2d6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -25,8 +25,10 @@ struct ath_buf; #ifdef CONFIG_ATH9K_DEBUGFS #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ +#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++ #else #define TX_STAT_INC(q, c) do { } while (0) +#define RESET_STAT_INC(sc, type) do { } while (0) #endif #ifdef CONFIG_ATH9K_DEBUGFS @@ -171,10 +173,21 @@ struct ath_rx_stats { u8 rs_antenna; }; +enum ath_reset_type { + RESET_TYPE_BB_HANG, + RESET_TYPE_BB_WATCHDOG, + RESET_TYPE_FATAL_INT, + RESET_TYPE_TX_ERROR, + RESET_TYPE_TX_HANG, + RESET_TYPE_PLL_HANG, + __RESET_TYPE_MAX +}; + struct ath_stats { struct ath_interrupt_stats istats; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; + u32 reset[__RESET_TYPE_MAX]; }; #define ATH_DBG_MAX_SAMPLES 10 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 98831866575..366912f16ff 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -679,6 +679,16 @@ void ath9k_tasklet(unsigned long data) if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { +#ifdef CONFIG_ATH9K_DEBUGFS + enum ath_reset_type type; + + if (status & ATH9K_INT_FATAL) + type = RESET_TYPE_FATAL_INT; + else + type = RESET_TYPE_BB_WATCHDOG; + + RESET_STAT_INC(sc, type); +#endif ieee80211_queue_work(sc->hw, &sc->hw_reset_work); goto out; } @@ -995,8 +1005,10 @@ void ath_hw_check(struct work_struct *work) ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); if (busy >= 99) { - if (++sc->hw_busy_count >= 3) + if (++sc->hw_busy_count >= 3) { + RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + } } else if (busy >= 0) sc->hw_busy_count = 0; @@ -1016,6 +1028,7 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) /* Rx is hung for more than 500ms. Reset it */ ath_dbg(common, ATH_DBG_RESET, "Possible RX hang, resetting"); + RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); count = 0; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 49f1543ba13..7c4dae27931 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -564,8 +564,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); - if (needreset) + if (needreset) { + RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + } } static bool ath_lookup_legacy(struct ath_buf *bf) @@ -2206,6 +2208,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); + RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } -- cgit v1.2.3-70-g09d2 From 72d874c67c3cdf21ca95045baabac6a5843222d8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 8 Oct 2011 20:06:19 +0200 Subject: ath9k_hw: make ath9k_hw_set_interrupts use ah->imask by default Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 10 +++++----- drivers/net/wireless/ath/ath9k/gpio.c | 4 ++-- drivers/net/wireless/ath/ath9k/mac.c | 6 +++--- drivers/net/wireless/ath/ath9k/mac.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 10 +++++----- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/main.c') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 9cdeaebc844..a13cabb9543 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -515,7 +515,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, sc->sc_flags |= SC_OP_TSF_RESET; ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } @@ -643,7 +643,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, ath9k_hw_set_sta_beacon_timers(ah, &bs); ah->imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } @@ -679,7 +679,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } @@ -821,11 +821,11 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) if (status) { /* Re-enable beaconing */ ah->imask |= ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } else { /* Disable SWBA interrupt */ ah->imask &= ~ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); tasklet_kill(&sc->bcon_tasklet); ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); } diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index fd0f84ebdb5..61eee8c49a1 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -155,7 +155,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_disable_interrupts(ah); ah->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } } @@ -170,7 +170,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) if (timer_table->timer_mask.val == 0) { ath9k_hw_disable_interrupts(ah); ah->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 22f23eafe8b..835e81d8ef0 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -827,9 +827,9 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_enable_interrupts); -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) +void ath9k_hw_set_interrupts(struct ath_hw *ah) { - enum ath9k_int omask = ah->imask; + enum ath9k_int ints = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); @@ -837,7 +837,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); - ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + ath_dbg(common, ATH_DBG_INTERRUPT, "New interrupt mask 0x%x\n", ints); mask = ints & ATH9K_INT_COMMON; mask2 = 0; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 5eb4ee45432..736fcbee919 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -735,7 +735,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +void ath9k_hw_set_interrupts(struct ath_hw *ah); void ath9k_hw_enable_interrupts(struct ath_hw *ah); void ath9k_hw_disable_interrupts(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 366912f16ff..93fbe6f4089 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -273,7 +273,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) { @@ -833,7 +833,7 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & ATH9K_INT_RXEOL) { ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } if (status & ATH9K_INT_MIB) { @@ -1409,7 +1409,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ah->imask &= ~ATH9K_INT_TSFOOR; } - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); /* Set up ANI */ if (iter_data.naps > 0) { @@ -1584,7 +1584,7 @@ static void ath9k_enable_ps(struct ath_softc *sc) if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { ah->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } ath9k_hw_setrxabort(ah, 1); } @@ -1604,7 +1604,7 @@ static void ath9k_disable_ps(struct ath_softc *sc) PS_WAIT_FOR_TX_ACK); if (ah->imask & ATH9K_INT_TIM_TIMER) { ah->imask &= ~ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index d28a5ddc799..33d30792d7d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1970,7 +1970,7 @@ requeue: if (!(ah->imask & ATH9K_INT_RXEOL)) { ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } return 0; -- cgit v1.2.3-70-g09d2