Skip to content

Commit

Permalink
ath5k: Support synth-only channel change for AR2413/AR5413
Browse files Browse the repository at this point in the history
 * Add synth-only channel change for AR2413/5413. When we call
 ath5k_reset with a channel ath5k_hw_reset will first try to
 set channel on PHY while PHY is running instead of doing a normal
 full reset. To do this phy_init has to change to implement this
 functionality.

 * Clean up change_channel flag, what it really did was skip PCU
 registers when setting initvals. This is done because on reset
 PCU registers are not affected (except the registers we set
 in pcu init and -due to hw problems- TSF). Use a new skip_pcu
 flag that's not misleading instead. In the future we might use
 that to also skip PCU reset and save us the TSF etc problems
 (needs testing because standard practice is to reset everything).

 * Use fast channel change only when setting channel, and set skip_pcu
 to false only on init. When we reset the card due to DMA or PHY
 problems skip pcu but never do a fast channel change.

 Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>

Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Nick Kossifidis authored and John W. Linville committed Nov 30, 2010
1 parent 4c57581 commit 8aec7af
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 134 deletions.
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath5k/ath5k.h
Original file line number Diff line number Diff line change
Expand Up @@ -1183,7 +1183,7 @@ void ath5k_unregister_leds(struct ath5k_softc *sc);
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
int ath5k_hw_on_hold(struct ath5k_hw *ah);
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool change_channel);
struct ieee80211_channel *channel, bool fast, bool skip_pcu);
int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
bool is_set);
/* Power management functions */
Expand Down Expand Up @@ -1324,7 +1324,7 @@ void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode);
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
/* Init function */
int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 mode, u8 ee_mode, u8 freq);
u8 mode, u8 ee_mode, u8 freq, bool fast);

/*
* Functions used internaly
Expand Down
17 changes: 10 additions & 7 deletions drivers/net/wireless/ath/ath5k/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("0.6.0 (EXPERIMENTAL)");

static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
bool skip_pcu);
static int ath5k_beacon_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
Expand Down Expand Up @@ -496,7 +497,7 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
* hardware at the new frequency, and then re-enable
* the relevant bits of the h/w.
*/
return ath5k_reset(sc, chan);
return ath5k_reset(sc, chan, true);
}

static void
Expand Down Expand Up @@ -2327,7 +2328,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
if (needreset) {
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
"TX queues stuck, resetting\n");
ath5k_reset(sc, sc->curchan);
ath5k_reset(sc, NULL, true);
}

ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Expand Down Expand Up @@ -2407,7 +2408,7 @@ ath5k_init(struct ath5k_softc *sc)
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;

ret = ath5k_reset(sc, NULL);
ret = ath5k_reset(sc, NULL, false);
if (ret)
goto done;

Expand Down Expand Up @@ -2506,7 +2507,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)
* This should be called with sc->lock.
*/
static int
ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
bool skip_pcu)
{
struct ath5k_hw *ah = sc->ah;
int ret;
Expand All @@ -2523,7 +2525,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
skip_pcu);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
Expand Down Expand Up @@ -2569,7 +2572,7 @@ static void ath5k_reset_work(struct work_struct *work)
reset_work);

mutex_lock(&sc->lock);
ath5k_reset(sc, sc->curchan);
ath5k_reset(sc, NULL, true);
mutex_unlock(&sc->lock);
}

Expand Down
64 changes: 49 additions & 15 deletions drivers/net/wireless/ath/ath5k/phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3223,20 +3223,46 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
\*************/

int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 mode, u8 ee_mode, u8 freq)
u8 mode, u8 ee_mode, u8 freq, bool fast)
{
struct ieee80211_channel *curr_channel;
int ret, i;
u32 phy_tst1;
bool fast_txp;
ret = 0;

/*
* Sanity check for fast flag
* Don't try fast channel change when changing modulation
* mode/band. We check for chip compatibility on
* ath5k_hw_reset.
*/
curr_channel = ah->ah_current_channel;
if (fast && (channel->hw_value != curr_channel->hw_value))
return -EINVAL;

/*
* On fast channel change we only set the synth parameters
* while PHY is running, enable calibration and skip the rest.
*/
if (fast) {
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
AR5K_PHY_RFBUS_REQ_REQUEST);
for (i = 0; i < 100; i++) {
if (ath5k_hw_reg_read(ah, AR5K_PHY_RFBUS_GRANT))
break;
udelay(5);
}
/* Failed */
if (i >= 100)
return -EIO;
}

/*
* If we don't change channel/mode skip
* tx powertable calculation and use the
* cached one.
*/
curr_channel = ah->ah_current_channel;
if ((channel->hw_value == curr_channel->hw_value) &&
(channel->center_freq == curr_channel->center_freq))
fast_txp = true;
Expand All @@ -3262,7 +3288,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
* any settings (5210 also only supports
* a/aturbo modes)
*/
if (ah->ah_version != AR5K_AR5210) {
if ((ah->ah_version != AR5K_AR5210) && !fast) {

/*
* Write initial RF gain settings
Expand Down Expand Up @@ -3308,7 +3334,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
AR5K_TXCFG_B_MODE);
}

} else {
} else if (ah->ah_version == AR5K_AR5210) {
mdelay(1);
/* Disable phy and wait */
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
Expand Down Expand Up @@ -3345,18 +3371,26 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
mdelay(1);
}

/*
* Perform ADC test to see if baseband is ready
* Set TX hold and check ADC test register
*/
phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
for (i = 0; i <= 20; i++) {
if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
break;
udelay(200);
if (fast)
/*
* Release RF Bus grant
*/
AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
AR5K_PHY_RFBUS_REQ_REQUEST);
else {
/*
* Perform ADC test to see if baseband is ready
* Set tx hold and check adc test register
*/
phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
for (i = 0; i <= 20; i++) {
if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
break;
udelay(200);
}
ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
}
ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);

/*
* Start automatic gain control calibration
Expand Down
Loading

0 comments on commit 8aec7af

Please sign in to comment.