Skip to content

Commit

Permalink
ath9k: Streamline attach/detach
Browse files Browse the repository at this point in the history
Simplify attach and detach routines by consolidating
the stop and suspend functions.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Sujith authored and John W. Linville committed Nov 10, 2008
1 parent 50fdae2 commit 9c84b79
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 248 deletions.
218 changes: 78 additions & 140 deletions drivers/net/wireless/ath9k/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc)
struct ath9k_channel *c;

/* Fill in ah->ah_channels */
if (!ath9k_regd_init_channels(ah,
ATH_CHAN_MAX,
(u32 *)&nchan,
regclassids,
ATH_REGCLASSIDS_MAX,
&nregclass,
CTRY_DEFAULT,
false,
1)) {
if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
regclassids, ATH_REGCLASSIDS_MAX,
&nregclass, CTRY_DEFAULT, false, 1)) {
u32 rd = ah->ah_currentRD;

DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to collect channel list; "
"regdomain likely %u country code %u\n",
Expand All @@ -217,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc)
chan_2ghz[a].max_power = c->maxTxPower;

if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
chan_2ghz[a].flags |=
IEEE80211_CHAN_NO_IBSS;
chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
if (c->channelFlags & CHANNEL_PASSIVE)
chan_2ghz[a].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;

band_2ghz->n_channels = ++a;

DPRINTF(sc, ATH_DBG_CONFIG,
"%s: 2MHz channel: %d, "
"channelFlags: 0x%x\n",
__func__,
c->channel,
c->channelFlags);
__func__, c->channel, c->channelFlags);
} else if (IS_CHAN_5GHZ(c)) {
chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
chan_5ghz[b].center_freq = c->channel;
chan_5ghz[b].max_power = c->maxTxPower;

if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
chan_5ghz[b].flags |=
IEEE80211_CHAN_NO_IBSS;
chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
if (c->channelFlags & CHANNEL_PASSIVE)
chan_5ghz[b].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;

band_5ghz->n_channels = ++b;

DPRINTF(sc, ATH_DBG_CONFIG,
"%s: 5MHz channel: %d, "
"channelFlags: 0x%x\n",
__func__,
c->channel,
c->channelFlags);
__func__, c->channel, c->channelFlags);
}
}

Expand Down Expand Up @@ -291,44 +276,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
return ATH9K_MODE_11B;
}

/*
* Stop the device, grabbing the top-level lock to protect
* against concurrent entry through ath_init (which can happen
* if another thread does a system call and the thread doing the
* stop is preempted).
*/

static int ath_stop(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;

DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
__func__, sc->sc_flags & SC_OP_INVALID);

/*
* Shutdown the hardware and driver:
* stop output from above
* turn off timers
* disable interrupts
* clear transmit machinery
* clear receive machinery
* turn off the radio
* reclaim beacon resources
*
* Note that some of this work is not possible if the
* hardware is gone (invalid).
*/

ath_draintxq(sc, false);
if (!(sc->sc_flags & SC_OP_INVALID)) {
ath_stoprecv(sc);
ath9k_hw_phy_disable(ah);
} else
sc->sc_rxlink = NULL;

return 0;
}

/*
* Set the current channel
*
Expand Down Expand Up @@ -650,16 +597,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
__func__, sc->sc_ah->ah_opmode);

/*
* Stop anything previously setup. This is safe
* whether this is the first time through or not.
*/
ath_stop(sc);

/* Initialize chanmask selection */
sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;

/* Reset SERDES registers */
ath9k_hw_configpcipowersave(ah, 0);

Expand All @@ -685,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
goto done;
}
spin_unlock_bh(&sc->sc_resetlock);

/*
* This is needed only to setup initial state
* but it's best done after a reset.
Expand All @@ -704,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
error = -EIO;
goto done;
}

/* Setup our intr mask. */
sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
Expand Down Expand Up @@ -733,30 +672,61 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
(sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
!sc->sc_config.swBeaconProcess)
sc->sc_imask |= ATH9K_INT_TIM;

ath_setcurmode(sc, ath_chan2mode(initial_chan));

/*
* Don't enable interrupts here as we've not yet built our
* vap and node data structures, which will be needed as soon
* as we start receiving.
*/
ath_setcurmode(sc, ath_chan2mode(initial_chan));

/* XXX: we must make sure h/w is ready and clear invalid flag
* before turning on interrupt. */
sc->sc_flags &= ~SC_OP_INVALID;

ieee80211_wake_queues(sc->hw);
done:
return error;
}

void ath_stop(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;

DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__);

ieee80211_stop_queues(sc->hw);

/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
ath9k_hw_set_interrupts(ah, 0);

if (!(sc->sc_flags & SC_OP_INVALID)) {
ath_draintxq(sc, false);
ath_stoprecv(sc);
ath9k_hw_phy_disable(ah);
} else
sc->sc_rxlink = NULL;

#ifdef CONFIG_RFKILL
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
#endif
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);
ath9k_hw_configpcipowersave(sc->sc_ah, 1);

sc->sc_flags |= SC_OP_INVALID;
}

int ath_reset(struct ath_softc *sc, bool retry_tx)
{
struct ath_hal *ah = sc->sc_ah;
int status;
int error = 0;

ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
ath_draintxq(sc, retry_tx); /* stop xmit */
ath_stoprecv(sc); /* stop recv */
ath_flushrecv(sc); /* flush recv queue */
ath9k_hw_set_interrupts(ah, 0);
ath_draintxq(sc, retry_tx);
ath_stoprecv(sc);
ath_flushrecv(sc);

/* Reset chip */
spin_lock_bh(&sc->sc_resetlock);
Expand All @@ -771,7 +741,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
}
spin_unlock_bh(&sc->sc_resetlock);

if (ath_startrecv(sc) != 0) /* restart recv */
if (ath_startrecv(sc) != 0)
DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to start recv logic\n", __func__);

Expand Down Expand Up @@ -804,29 +774,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
return error;
}

int ath_suspend(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;

/* No I/O if device has been surprise removed */
if (sc->sc_flags & SC_OP_INVALID)
return -EIO;

/* Shut off the interrupt before setting sc->sc_invalid to '1' */
ath9k_hw_set_interrupts(ah, 0);

/* XXX: we must make sure h/w will not generate any interrupt
* before setting the invalid flag. */
sc->sc_flags |= SC_OP_INVALID;

/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);

ath9k_hw_configpcipowersave(sc->sc_ah, 1);

return 0;
}

/* Interrupt handler. Most of the actual processing is deferred.
* It's the caller's responsibility to ensure the chip is awake. */

Expand Down Expand Up @@ -994,11 +941,9 @@ int ath_init(u16 devid, struct ath_softc *sc)

/* XXX: hardware will not be ready until ath_open() being called */
sc->sc_flags |= SC_OP_INVALID;

sc->sc_debug = DBG_DEFAULT;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);

/* Initialize tasklet */
spin_lock_init(&sc->sc_resetlock);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
(unsigned long)sc);
Expand All @@ -1011,8 +956,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
/* XXX assert csz is non-zero */
sc->sc_cachelsz = csz << 2; /* convert to bytes */

spin_lock_init(&sc->sc_resetlock);

ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
if (ah == NULL) {
DPRINTF(sc, ATH_DBG_FATAL,
Expand All @@ -1023,10 +966,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
}
sc->sc_ah = ah;

/* Initializes the noise floor to a reasonable default value.
* Later on this will be updated during ANI processing. */
sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;

/* Get the hardware key cache size. */
sc->sc_keymax = ah->ah_caps.keycache_size;
if (sc->sc_keymax > ATH_KEYMAX) {
Expand Down Expand Up @@ -1054,17 +993,14 @@ int ath_init(u16 devid, struct ath_softc *sc)
set_bit(i + 64, sc->sc_keymap);
set_bit(i + 32 + 64, sc->sc_keymap);
}
/*
* Collect the channel list using the default country
* code and including outdoor channels. The 802.11 layer
* is resposible for filtering this list based on settings
* like the phy mode.
*/

/* Collect the channel list using the default country code */

error = ath_setup_channels(sc);
if (error)
goto bad;

/* default to STA mode */
/* default to MONITOR mode */
sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;

/* Setup rate tables */
Expand Down Expand Up @@ -1134,6 +1070,10 @@ int ath_init(u16 devid, struct ath_softc *sc)
goto bad2;
}

/* Initializes the noise floor to a reasonable default value.
* Later on this will be updated during ANI processing. */

sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);

sc->sc_rc = ath_rate_attach(ah);
Expand Down Expand Up @@ -1194,6 +1134,7 @@ int ath_init(u16 devid, struct ath_softc *sc)
ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
}

sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */

/* initialize beacon slots */
Expand All @@ -1208,6 +1149,22 @@ int ath_init(u16 devid, struct ath_softc *sc)
ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
#endif

/* setup channels and rates */

sc->sbands[IEEE80211_BAND_2GHZ].channels =
sc->channels[IEEE80211_BAND_2GHZ];
sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
sc->rates[IEEE80211_BAND_2GHZ];
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;

if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
sc->sbands[IEEE80211_BAND_5GHZ].channels =
sc->channels[IEEE80211_BAND_5GHZ];
sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
sc->rates[IEEE80211_BAND_5GHZ];
sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
}

return 0;
bad2:
/* cleanup tx queues */
Expand All @@ -1217,27 +1174,8 @@ int ath_init(u16 devid, struct ath_softc *sc)
bad:
if (ah)
ath9k_hw_detach(ah);
return error;
}

void ath_deinit(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
int i;

DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);

tasklet_kill(&sc->intr_tq);
tasklet_kill(&sc->bcon_tasklet);
ath_stop(sc);
if (!(sc->sc_flags & SC_OP_INVALID))
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
ath_rate_detach(sc->sc_rc);
/* cleanup tx queues */
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->sc_txq[i]);
ath9k_hw_detach(ah);
return error;
}

/*******************/
Expand Down
3 changes: 1 addition & 2 deletions drivers/net/wireless/ath9k/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -997,9 +997,8 @@ struct ath_softc {
};

int ath_init(u16 devid, struct ath_softc *sc);
void ath_deinit(struct ath_softc *sc);
int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
int ath_suspend(struct ath_softc *sc);
void ath_stop(struct ath_softc *sc);
irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc, bool retry_tx);
int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
Expand Down
Loading

0 comments on commit 9c84b79

Please sign in to comment.