Commit 9c84b797 authored by Sujith's avatar Sujith Committed by John W. Linville

ath9k: Streamline attach/detach

Simplify attach and detach routines by consolidating
the stop and suspend functions.
Signed-off-by: default avatarSujith <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 50fdae2c
...@@ -186,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc) ...@@ -186,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc)
struct ath9k_channel *c; struct ath9k_channel *c;
/* Fill in ah->ah_channels */ /* Fill in ah->ah_channels */
if (!ath9k_regd_init_channels(ah, if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
ATH_CHAN_MAX, regclassids, ATH_REGCLASSIDS_MAX,
(u32 *)&nchan, &nregclass, CTRY_DEFAULT, false, 1)) {
regclassids,
ATH_REGCLASSIDS_MAX,
&nregclass,
CTRY_DEFAULT,
false,
1)) {
u32 rd = ah->ah_currentRD; u32 rd = ah->ah_currentRD;
DPRINTF(sc, ATH_DBG_FATAL, DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to collect channel list; " "%s: unable to collect channel list; "
"regdomain likely %u country code %u\n", "regdomain likely %u country code %u\n",
...@@ -217,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc) ...@@ -217,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc)
chan_2ghz[a].max_power = c->maxTxPower; chan_2ghz[a].max_power = c->maxTxPower;
if (c->privFlags & CHANNEL_DISALLOW_ADHOC) if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
chan_2ghz[a].flags |= chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IBSS;
if (c->channelFlags & CHANNEL_PASSIVE) if (c->channelFlags & CHANNEL_PASSIVE)
chan_2ghz[a].flags |= chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_PASSIVE_SCAN;
band_2ghz->n_channels = ++a; band_2ghz->n_channels = ++a;
DPRINTF(sc, ATH_DBG_CONFIG, DPRINTF(sc, ATH_DBG_CONFIG,
"%s: 2MHz channel: %d, " "%s: 2MHz channel: %d, "
"channelFlags: 0x%x\n", "channelFlags: 0x%x\n",
__func__, __func__, c->channel, c->channelFlags);
c->channel,
c->channelFlags);
} else if (IS_CHAN_5GHZ(c)) { } else if (IS_CHAN_5GHZ(c)) {
chan_5ghz[b].band = IEEE80211_BAND_5GHZ; chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
chan_5ghz[b].center_freq = c->channel; chan_5ghz[b].center_freq = c->channel;
chan_5ghz[b].max_power = c->maxTxPower; chan_5ghz[b].max_power = c->maxTxPower;
if (c->privFlags & CHANNEL_DISALLOW_ADHOC) if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
chan_5ghz[b].flags |= chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IBSS;
if (c->channelFlags & CHANNEL_PASSIVE) if (c->channelFlags & CHANNEL_PASSIVE)
chan_5ghz[b].flags |= chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_PASSIVE_SCAN;
band_5ghz->n_channels = ++b; band_5ghz->n_channels = ++b;
DPRINTF(sc, ATH_DBG_CONFIG, DPRINTF(sc, ATH_DBG_CONFIG,
"%s: 5MHz channel: %d, " "%s: 5MHz channel: %d, "
"channelFlags: 0x%x\n", "channelFlags: 0x%x\n",
__func__, __func__, c->channel, c->channelFlags);
c->channel,
c->channelFlags);
} }
} }
...@@ -291,44 +276,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) ...@@ -291,44 +276,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
return ATH9K_MODE_11B; 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 * Set the current channel
* *
...@@ -650,16 +597,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) ...@@ -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", DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
__func__, sc->sc_ah->ah_opmode); __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 */ /* Reset SERDES registers */
ath9k_hw_configpcipowersave(ah, 0); ath9k_hw_configpcipowersave(ah, 0);
...@@ -685,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) ...@@ -685,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
goto done; goto done;
} }
spin_unlock_bh(&sc->sc_resetlock); spin_unlock_bh(&sc->sc_resetlock);
/* /*
* This is needed only to setup initial state * This is needed only to setup initial state
* but it's best done after a reset. * but it's best done after a reset.
...@@ -704,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) ...@@ -704,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
error = -EIO; error = -EIO;
goto done; goto done;
} }
/* Setup our intr mask. */ /* Setup our intr mask. */
sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
| ATH9K_INT_RXEOL | ATH9K_INT_RXORN | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
...@@ -733,30 +672,61 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) ...@@ -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_ah->ah_opmode == ATH9K_M_STA) &&
!sc->sc_config.swBeaconProcess) !sc->sc_config.swBeaconProcess)
sc->sc_imask |= ATH9K_INT_TIM; 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 * Don't enable interrupts here as we've not yet built our
* vap and node data structures, which will be needed as soon * vap and node data structures, which will be needed as soon
* as we start receiving. * 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; sc->sc_flags &= ~SC_OP_INVALID;
ieee80211_wake_queues(sc->hw);
done: done:
return error; 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) int ath_reset(struct ath_softc *sc, bool retry_tx)
{ {
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
int status; int status;
int error = 0; int error = 0;
ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ ath9k_hw_set_interrupts(ah, 0);
ath_draintxq(sc, retry_tx); /* stop xmit */ ath_draintxq(sc, retry_tx);
ath_stoprecv(sc); /* stop recv */ ath_stoprecv(sc);
ath_flushrecv(sc); /* flush recv queue */ ath_flushrecv(sc);
/* Reset chip */ /* Reset chip */
spin_lock_bh(&sc->sc_resetlock); spin_lock_bh(&sc->sc_resetlock);
...@@ -771,7 +741,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ...@@ -771,7 +741,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
} }
spin_unlock_bh(&sc->sc_resetlock); spin_unlock_bh(&sc->sc_resetlock);
if (ath_startrecv(sc) != 0) /* restart recv */ if (ath_startrecv(sc) != 0)
DPRINTF(sc, ATH_DBG_FATAL, DPRINTF(sc, ATH_DBG_FATAL,
"%s: unable to start recv logic\n", __func__); "%s: unable to start recv logic\n", __func__);
...@@ -804,29 +774,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ...@@ -804,29 +774,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
return error; 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. /* Interrupt handler. Most of the actual processing is deferred.
* It's the caller's responsibility to ensure the chip is awake. */ * It's the caller's responsibility to ensure the chip is awake. */
...@@ -994,11 +941,9 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -994,11 +941,9 @@ int ath_init(u16 devid, struct ath_softc *sc)
/* XXX: hardware will not be ready until ath_open() being called */ /* XXX: hardware will not be ready until ath_open() being called */
sc->sc_flags |= SC_OP_INVALID; sc->sc_flags |= SC_OP_INVALID;
sc->sc_debug = DBG_DEFAULT; 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->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
(unsigned long)sc); (unsigned long)sc);
...@@ -1011,8 +956,6 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1011,8 +956,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
/* XXX assert csz is non-zero */ /* XXX assert csz is non-zero */
sc->sc_cachelsz = csz << 2; /* convert to bytes */ sc->sc_cachelsz = csz << 2; /* convert to bytes */
spin_lock_init(&sc->sc_resetlock);
ah = ath9k_hw_attach(devid, sc, sc->mem, &status); ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
if (ah == NULL) { if (ah == NULL) {
DPRINTF(sc, ATH_DBG_FATAL, DPRINTF(sc, ATH_DBG_FATAL,
...@@ -1023,10 +966,6 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1023,10 +966,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
} }
sc->sc_ah = ah; 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. */ /* Get the hardware key cache size. */
sc->sc_keymax = ah->ah_caps.keycache_size; sc->sc_keymax = ah->ah_caps.keycache_size;
if (sc->sc_keymax > ATH_KEYMAX) { if (sc->sc_keymax > ATH_KEYMAX) {
...@@ -1054,17 +993,14 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1054,17 +993,14 @@ int ath_init(u16 devid, struct ath_softc *sc)
set_bit(i + 64, sc->sc_keymap); set_bit(i + 64, sc->sc_keymap);
set_bit(i + 32 + 64, sc->sc_keymap); set_bit(i + 32 + 64, sc->sc_keymap);
} }
/*
* Collect the channel list using the default country /* Collect the channel list using the default country code */
* code and including outdoor channels. The 802.11 layer
* is resposible for filtering this list based on settings
* like the phy mode.
*/
error = ath_setup_channels(sc); error = ath_setup_channels(sc);
if (error) if (error)
goto bad; goto bad;
/* default to STA mode */ /* default to MONITOR mode */
sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
/* Setup rate tables */ /* Setup rate tables */
...@@ -1134,6 +1070,10 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1134,6 +1070,10 @@ int ath_init(u16 devid, struct ath_softc *sc)
goto bad2; 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); setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
sc->sc_rc = ath_rate_attach(ah); sc->sc_rc = ath_rate_attach(ah);
...@@ -1194,6 +1134,7 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1194,6 +1134,7 @@ int ath_init(u16 devid, struct ath_softc *sc)
ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
} }
sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
/* initialize beacon slots */ /* initialize beacon slots */
...@@ -1208,6 +1149,22 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1208,6 +1149,22 @@ int ath_init(u16 devid, struct ath_softc *sc)
ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
#endif #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; return 0;
bad2: bad2:
/* cleanup tx queues */ /* cleanup tx queues */
...@@ -1217,27 +1174,8 @@ int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1217,27 +1174,8 @@ int ath_init(u16 devid, struct ath_softc *sc)
bad: bad:
if (ah) if (ah)
ath9k_hw_detach(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__); return error;
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);
} }
/*******************/ /*******************/
......
...@@ -997,9 +997,8 @@ struct ath_softc { ...@@ -997,9 +997,8 @@ struct ath_softc {
}; };
int ath_init(u16 devid, struct ath_softc *sc); 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_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); irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_reset(struct ath_softc *sc, bool retry_tx);
int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
......
...@@ -616,6 +616,7 @@ static void ath_init_leds(struct ath_softc *sc) ...@@ -616,6 +616,7 @@ static void ath_init_leds(struct ath_softc *sc)
} }
#ifdef CONFIG_RFKILL #ifdef CONFIG_RFKILL
/*******************/ /*******************/
/* Rfkill */ /* Rfkill */
/*******************/ /*******************/
...@@ -816,43 +817,72 @@ static void ath_deinit_rfkill(struct ath_softc *sc) ...@@ -816,43 +817,72 @@ static void ath_deinit_rfkill(struct ath_softc *sc)
sc->rf_kill.rfkill = NULL; sc->rf_kill.rfkill = NULL;
} }
} }
static int ath_start_rfkill_poll(struct ath_softc *sc)
{
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
queue_delayed_work(sc->hw->workqueue,
&sc->rf_kill.rfkill_poll, 0);
if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
if (rfkill_register(sc->rf_kill.rfkill)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to register rfkill\n");
rfkill_free(sc->rf_kill.rfkill);
/* Deinitialize the device */
if (sc->pdev->irq)
free_irq(sc->pdev->irq, sc);
ath_detach(sc);
pci_iounmap(sc->pdev, sc->mem);
pci_release_region(sc->pdev, 0);
pci_disable_device(sc->pdev);
ieee80211_free_hw(hw);
return -EIO;
} else {
sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
}
}
return 0;
}
#endif /* CONFIG_RFKILL */ #endif /* CONFIG_RFKILL */
static int ath_detach(struct ath_softc *sc) static void ath_detach(struct ath_softc *sc)
{ {
struct ieee80211_hw *hw = sc->hw; struct ieee80211_hw *hw = sc->hw;
int i = 0;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
/* Deinit LED control */ ieee80211_unregister_hw(hw);
ath_deinit_leds(sc); ath_deinit_leds(sc);
#ifdef CONFIG_RFKILL #ifdef CONFIG_RFKILL
/* deinit rfkill */
ath_deinit_rfkill(sc); ath_deinit_rfkill(sc);
#endif #endif
/* Unregister hw */
ieee80211_unregister_hw(hw);
/* unregister Rate control */
ath_rate_control_unregister(); ath_rate_control_unregister();
ath_rate_detach(sc->sc_rc);
/* tx/rx cleanup */
ath_rx_cleanup(sc); ath_rx_cleanup(sc);
ath_tx_cleanup(sc); ath_tx_cleanup(sc);
/* Deinit */ tasklet_kill(&sc->intr_tq);
tasklet_kill(&sc->bcon_tasklet);
ath_deinit(sc); if (!(sc->sc_flags & SC_OP_INVALID))
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
return 0; /* 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(sc->sc_ah);
} }
static int ath_attach(u16 devid, static int ath_attach(u16 devid, struct ath_softc *sc)
struct ath_softc *sc)
{ {
struct ieee80211_hw *hw = sc->hw; struct ieee80211_hw *hw = sc->hw;
int error = 0; int error = 0;
...@@ -867,36 +897,15 @@ static int ath_attach(u16 devid, ...@@ -867,36 +897,15 @@ static int ath_attach(u16 devid,
SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
/* setup channels and rates */ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
sc->sbands[IEEE80211_BAND_2GHZ].channels = IEEE80211_HW_SIGNAL_DBM |
sc->channels[IEEE80211_BAND_2GHZ]; IEEE80211_HW_AMPDU_AGGREGATION;
sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
sc->rates[IEEE80211_BAND_2GHZ];
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
/* Setup HT capabilities for 2.4Ghz*/
setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&sc->sbands[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;
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
/* Setup HT capabilities for 5Ghz*/
setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
hw->wiphy->bands[IEEE80211_BAND_5GHZ] = hw->wiphy->interface_modes =
&sc->sbands[IEEE80211_BAND_5GHZ]; BIT(NL80211_IFTYPE_AP) |
} BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
hw->queues = 4; hw->queues = 4;
hw->sta_data_size = sizeof(struct ath_node); hw->sta_data_size = sizeof(struct ath_node);
...@@ -913,6 +922,17 @@ static int ath_attach(u16 devid, ...@@ -913,6 +922,17 @@ static int ath_attach(u16 devid,
goto bad; goto bad;
} }
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ];
if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ];
error = ieee80211_register_hw(hw); error = ieee80211_register_hw(hw);
if (error != 0) { if (error != 0) {
ath_rate_control_unregister(); ath_rate_control_unregister();
...@@ -963,49 +983,26 @@ static int ath9k_start(struct ieee80211_hw *hw) ...@@ -963,49 +983,26 @@ static int ath9k_start(struct ieee80211_hw *hw)
pos = ath_get_channel(sc, curchan); pos = ath_get_channel(sc, curchan);
if (pos == -1) { if (pos == -1) {
DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
return -EINVAL; error = -EINVAL;
goto exit;
} }
sc->sc_ah->ah_channels[pos].chanmode = sc->sc_ah->ah_channels[pos].chanmode =
(curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
/* open ath_dev */
error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
if (error) { if (error) {
DPRINTF(sc, ATH_DBG_FATAL, DPRINTF(sc, ATH_DBG_FATAL,
"%s: Unable to complete ath_open\n", __func__); "%s: Unable to complete ath_open\n", __func__);
return error; goto exit;
} }
#ifdef CONFIG_RFKILL #ifdef CONFIG_RFKILL
/* Start rfkill polling */ error = ath_start_rfkill_poll(sc);
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
queue_delayed_work(sc->hw->workqueue,
&sc->rf_kill.rfkill_poll, 0);
if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
if (rfkill_register(sc->rf_kill.rfkill)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to register rfkill\n");
rfkill_free(sc->rf_kill.rfkill);
/* Deinitialize the device */
if (sc->pdev->irq)
free_irq(sc->pdev->irq, sc);
ath_detach(sc);
pci_iounmap(sc->pdev, sc->mem);
pci_release_region(sc->pdev, 0);
pci_disable_device(sc->pdev);
ieee80211_free_hw(hw);
return -EIO;
} else {
sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
}
}
#endif #endif
ieee80211_wake_queues(hw); exit:
return 0; return error;
} }
static int ath9k_tx(struct ieee80211_hw *hw, static int ath9k_tx(struct ieee80211_hw *hw,
...@@ -1065,21 +1062,15 @@ static int ath9k_tx(struct ieee80211_hw *hw, ...@@ -1065,21 +1062,15 @@ static int ath9k_tx(struct ieee80211_hw *hw,
static void ath9k_stop(struct ieee80211_hw *hw) static void ath9k_stop(struct ieee80211_hw *hw)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
int error;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
error = ath_suspend(sc); if (sc->sc_flags & SC_OP_INVALID) {
if (error) DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__);
DPRINTF(sc, ATH_DBG_CONFIG, return;
"%s: Device is no longer present\n", __func__); }
ieee80211_stop_queues(hw); ath_stop(sc);
#ifdef CONFIG_RFKILL DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
#endif
} }
static int ath9k_add_interface(struct ieee80211_hw *hw, static int ath9k_add_interface(struct ieee80211_hw *hw,
...@@ -1643,17 +1634,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1643,17 +1634,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto bad2; goto bad2;
} }
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
SET_IEEE80211_DEV(hw, &pdev->dev); SET_IEEE80211_DEV(hw, &pdev->dev);
pci_set_drvdata(pdev, hw); pci_set_drvdata(pdev, hw);
...@@ -1701,17 +1681,10 @@ static void ath_pci_remove(struct pci_dev *pdev) ...@@ -1701,17 +1681,10 @@ static void ath_pci_remove(struct pci_dev *pdev)
{ {
struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
enum ath9k_int status;
if (pdev->irq) {
ath9k_hw_set_interrupts(sc->sc_ah, 0);
/* clear the ISR */
ath9k_hw_getisr(sc->sc_ah, &status);
sc->sc_flags |= SC_OP_INVALID;
free_irq(pdev->irq, sc);
}
ath_detach(sc); ath_detach(sc);
if (pdev->irq)
free_irq(pdev->irq, sc);
pci_iounmap(pdev, sc->mem); pci_iounmap(pdev, sc->mem);
pci_release_region(pdev, 0); pci_release_region(pdev, 0);
pci_disable_device(pdev); pci_disable_device(pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment