Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 300613
b: refs/heads/master
c: 01e1891
h: refs/heads/master
i:
  300611: 41da50d
v: v3
  • Loading branch information
Rajkumar Manoharan authored and John W. Linville committed Apr 9, 2012
1 parent 6b01f0f commit 407a08d
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 54da20d83f0e7fe87b75aec44bc2b1448d119320
refs/heads/master: 01e189182d62d6ee3603233fc88f9235e9830b92
3 changes: 3 additions & 0 deletions trunk/drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,8 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
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_rx_poll(unsigned long data);
void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
void ath_start_ani(struct ath_common *common);
Expand Down Expand Up @@ -670,6 +672,7 @@ struct ath_softc {
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;
struct delayed_work hw_pll_work;
struct timer_list rx_poll_timer;

#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
struct ath_btcoex btcoex;
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/wireless/ath/ath9k/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ enum ath_reset_type {
RESET_TYPE_TX_ERROR,
RESET_TYPE_TX_HANG,
RESET_TYPE_PLL_HANG,
RESET_TYPE_MAC_HANG,
__RESET_TYPE_MAX
};

Expand Down
73 changes: 73 additions & 0 deletions trunk/drivers/net/wireless/ath/ath9k/hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1491,11 +1491,84 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
}
}

static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states,
int *hang_state, int *hang_pos)
{
static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */
u32 chain_state, dcs_pos, i;

for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) {
chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f;
for (i = 0; i < 3; i++) {
if (chain_state == dcu_chain_state[i]) {
*hang_state = chain_state;
*hang_pos = dcs_pos;
return true;
}
}
}
return false;
}

#define DCU_COMPLETE_STATE 1
#define DCU_COMPLETE_STATE_MASK 0x3
#define NUM_STATUS_READS 50
static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah)
{
u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4;
u32 i, hang_pos, hang_state, num_state = 6;

comp_state = REG_READ(ah, AR_DMADBG_6);

if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) {
ath_dbg(ath9k_hw_common(ah), RESET,
"MAC Hang signature not found at DCU complete\n");
return false;
}

chain_state = REG_READ(ah, dcs_reg);
if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
goto hang_check_iter;

dcs_reg = AR_DMADBG_5;
num_state = 4;
chain_state = REG_READ(ah, dcs_reg);
if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
goto hang_check_iter;

ath_dbg(ath9k_hw_common(ah), RESET,
"MAC Hang signature 1 not found\n");
return false;

hang_check_iter:
ath_dbg(ath9k_hw_common(ah), RESET,
"DCU registers: chain %08x complete %08x Hang: state %d pos %d\n",
chain_state, comp_state, hang_state, hang_pos);

for (i = 0; i < NUM_STATUS_READS; i++) {
chain_state = REG_READ(ah, dcs_reg);
chain_state = (chain_state >> (5 * hang_pos)) & 0x1f;
comp_state = REG_READ(ah, AR_DMADBG_6);

if (((comp_state & DCU_COMPLETE_STATE_MASK) !=
DCU_COMPLETE_STATE) ||
(chain_state != hang_state))
return false;
}

ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n");

return true;
}

bool ath9k_hw_check_alive(struct ath_hw *ah)
{
int count = 50;
u32 reg;

if (AR_SREV_9300(ah))
return !ath9k_hw_detect_mac_hang(ah);

if (AR_SREV_9285_12_OR_LATER(ah))
return true;

Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/wireless/ath/ath9k/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
goto error_world;
}

setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;

ath_init_leds(sc);
Expand Down
48 changes: 44 additions & 4 deletions trunk/drivers/net/wireless/ath/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)

sc->hw_busy_count = 0;
del_timer_sync(&common->ani.timer);
del_timer_sync(&sc->rx_poll_timer);

ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah);
Expand Down Expand Up @@ -284,6 +285,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)

ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
ath_start_rx_poll(sc, 3);
if (!common->disable_ani)
ath_start_ani(common);
}
Expand Down Expand Up @@ -914,10 +916,19 @@ void ath_hw_check(struct work_struct *work)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long flags;
int busy;
u8 is_alive, nbeacon = 1;

ath9k_ps_wakeup(sc);
if (ath9k_hw_check_alive(sc->sc_ah))
is_alive = ath9k_hw_check_alive(sc->sc_ah);

if (is_alive && !AR_SREV_9300(sc->sc_ah))
goto out;
else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
ath_dbg(common, RESET,
"DCU stuck is detected. Schedule chip reset\n");
RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
goto sched_reset;
}

spin_lock_irqsave(&common->cc_lock, flags);
busy = ath_update_survey_stats(sc);
Expand All @@ -928,12 +939,18 @@ void ath_hw_check(struct work_struct *work)
if (busy >= 99) {
if (++sc->hw_busy_count >= 3) {
RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
goto sched_reset;
}

} else if (busy >= 0)
} else if (busy >= 0) {
sc->hw_busy_count = 0;
nbeacon = 3;
}

ath_start_rx_poll(sc, nbeacon);
goto out;

sched_reset:
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
out:
ath9k_ps_restore(sc);
}
Expand Down Expand Up @@ -1153,6 +1170,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);

ath_cancel_work(sc);
del_timer_sync(&sc->rx_poll_timer);

if (sc->sc_flags & SC_OP_INVALID) {
ath_dbg(common, ANY, "Device not present\n");
Expand Down Expand Up @@ -1385,6 +1403,24 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
}
}

void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
{
if (!AR_SREV_9300(sc->sc_ah))
return;

if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
return;

mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
(nbeacon * sc->cur_beacon_conf.beacon_interval));
}

void ath_rx_poll(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;

ieee80211_queue_work(sc->hw, &sc->hw_check_work);
}

static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
Expand Down Expand Up @@ -1906,6 +1942,8 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;

ath_start_rx_poll(sc, 3);

if (!common->disable_ani) {
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
Expand Down Expand Up @@ -1945,6 +1983,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);
del_timer_sync(&sc->rx_poll_timer);
memset(&sc->caldata, 0, sizeof(sc->caldata));
}
}
Expand Down Expand Up @@ -1988,6 +2027,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
} else {
sc->sc_flags &= ~SC_OP_ANI_RUN;
del_timer_sync(&common->ani.timer);
del_timer_sync(&sc->rx_poll_timer);
}
}

Expand Down
4 changes: 4 additions & 0 deletions trunk/drivers/net/wireless/ath/ath9k/recv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (retval)
goto requeue_drop_frag;

if (rs.is_mybeacon) {
sc->hw_busy_count = 0;
ath_start_rx_poll(sc, 3);
}
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
Expand Down

0 comments on commit 407a08d

Please sign in to comment.