aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath9k/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c115
1 files changed, 76 insertions, 39 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index a9e43f7a23f..3dc7b5a13e6 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -384,7 +384,7 @@ static void ath_ani_calibrate(unsigned long data)
if (longcal || shortcal || aniflag) {
/* Call ANI routine if necessary */
if (aniflag)
- ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan);
+ ath9k_hw_ani_monitor(ah, ah->curchan);
/* Perform calibration if necessary */
if (longcal || shortcal) {
@@ -439,8 +439,8 @@ static void ath_start_ani(struct ath_softc *sc)
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
- if (is_ht ||
- (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
+ if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
+ (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) {
sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
} else {
@@ -506,6 +506,10 @@ static void ath9k_tasklet(unsigned long data)
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
}
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ if (status & ATH9K_INT_GENTIMER)
+ ath_gen_timer_isr(sc->sc_ah);
+
/* re-enable hardware interrupt */
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
ath9k_ps_restore(sc);
@@ -521,7 +525,8 @@ irqreturn_t ath_isr(int irq, void *dev)
ATH9K_INT_TX | \
ATH9K_INT_BMISS | \
ATH9K_INT_CST | \
- ATH9K_INT_TSFOOR)
+ ATH9K_INT_TSFOOR | \
+ ATH9K_INT_GENTIMER)
struct ath_softc *sc = dev;
struct ath_hw *ah = sc->sc_ah;
@@ -589,7 +594,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* it will clear whatever condition caused
* the interrupt.
*/
- ath9k_hw_procmibevent(ah, &sc->nodestats);
+ ath9k_hw_procmibevent(ah);
ath9k_hw_set_interrupts(ah, sc->imask);
}
@@ -940,10 +945,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
ath_beacon_config(sc, vif);
/* Reset rssi stats */
- sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
- sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
- sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
- sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
+ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
ath_start_ani(sc);
} else {
@@ -968,9 +970,9 @@ static void ath_led_blink_work(struct work_struct *work)
if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
(sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
else
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
(sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
ieee80211_queue_delayed_work(sc->hw,
@@ -1002,7 +1004,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
case LED_OFF:
if (led->led_type == ATH_LED_ASSOC ||
led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
(led->led_type == ATH_LED_RADIO));
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
if (led->led_type == ATH_LED_RADIO)
@@ -1017,7 +1019,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
ieee80211_queue_delayed_work(sc->hw,
&sc->ath_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
sc->sc_flags |= SC_OP_LED_ON;
} else {
sc->led_on_cnt++;
@@ -1062,7 +1064,7 @@ static void ath_deinit_leds(struct ath_softc *sc)
ath_unregister_led(&sc->tx_led);
ath_unregister_led(&sc->rx_led);
ath_unregister_led(&sc->radio_led);
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
}
static void ath_init_leds(struct ath_softc *sc)
@@ -1070,11 +1072,16 @@ static void ath_init_leds(struct ath_softc *sc)
char *trigger;
int ret;
+ if (AR_SREV_9287(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+ else
+ sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+
/* Configure gpio 1 for output */
- ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
@@ -1153,9 +1160,9 @@ void ath_radio_enable(struct ath_softc *sc)
ath9k_hw_set_interrupts(ah, sc->imask);
/* Enable LED */
- ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+ ath9k_hw_cfg_output(ah, ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 0);
ieee80211_wake_queues(sc->hw);
ath9k_ps_restore(sc);
@@ -1171,8 +1178,8 @@ void ath_radio_disable(struct ath_softc *sc)
ieee80211_stop_queues(sc->hw);
/* Disable LED */
- ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
- ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+ ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
/* Disable interrupts */
ath9k_hw_set_interrupts(ah, 0);
@@ -1277,6 +1284,10 @@ void ath_detach(struct ath_softc *sc)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+ if ((sc->btcoex_info.no_stomp_timer) &&
+ sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer);
+
ath9k_hw_detach(sc->sc_ah);
sc->sc_ah = NULL;
ath9k_exit_debug(sc);
@@ -1288,7 +1299,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_regulatory *reg = &sc->sc_ah->regulatory;
+ struct ath_regulatory *reg = &sc->common.regulatory;
return ath_reg_notifier_apply(wiphy, request, reg);
}
@@ -1299,7 +1310,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
* to allow the separation between hardware specific
* variables (now in ath_hw) and driver specific variables.
*/
-static int ath_init_softc(u16 devid, struct ath_softc *sc)
+static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
{
struct ath_hw *ah = NULL;
int r = 0, i;
@@ -1327,7 +1338,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
*/
ath_read_cachesize(sc, &csz);
/* XXX assert csz is non-zero */
- sc->cachelsz = csz << 2; /* convert to bytes */
+ sc->common.cachelsz = csz << 2; /* convert to bytes */
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
if (!ah) {
@@ -1337,6 +1348,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
ah->ah_sc = sc;
ah->hw_version.devid = devid;
+ ah->hw_version.subsysid = subsysid;
sc->sc_ah = ah;
r = ath9k_hw_init(ah);
@@ -1507,8 +1519,11 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
ARRAY_SIZE(ath9k_5ghz_chantable);
}
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
- ath9k_hw_btcoex_enable(sc->sc_ah);
+ if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) {
+ r = ath9k_hw_btcoex_init(ah);
+ if (r)
+ goto bad2;
+ }
return 0;
bad2:
@@ -1563,7 +1578,7 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
}
/* Device driver core initialization */
-int ath_init_device(u16 devid, struct ath_softc *sc)
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid)
{
struct ieee80211_hw *hw = sc->hw;
int error = 0, i;
@@ -1571,7 +1586,7 @@ int ath_init_device(u16 devid, struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
- error = ath_init_softc(devid, sc);
+ error = ath_init_softc(devid, sc, subsysid);
if (error != 0)
return error;
@@ -1581,12 +1596,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc)
ath_set_hw_capab(sc, hw);
- error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
+ error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
return error;
- reg = &sc->sc_ah->regulatory;
+ reg = &sc->common.regulatory;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
@@ -1865,7 +1880,7 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (chan->band == IEEE80211_BAND_2GHZ) {
ichan->chanmode = CHANNEL_G;
- ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
+ ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
} else {
ichan->chanmode = CHANNEL_A;
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
@@ -1990,6 +2005,17 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+ if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) &&
+ !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) {
+ ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ ath9k_hw_btcoex_enable(sc->sc_ah);
+
+ ath_pcie_aspm_disable(sc);
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_btcoex_timer_resume(sc, &sc->btcoex_info);
+ }
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -2100,6 +2126,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
+
aphy->state = ATH_WIPHY_INACTIVE;
cancel_delayed_work_sync(&sc->ath_led_blink_work);
@@ -2112,18 +2140,21 @@ static void ath9k_stop(struct ieee80211_hw *hw)
if (sc->sc_flags & SC_OP_INVALID) {
DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+ mutex_unlock(&sc->mutex);
return;
}
- mutex_lock(&sc->mutex);
-
- cancel_delayed_work_sync(&sc->tx_complete_work);
-
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
}
+ if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) {
+ ath9k_hw_btcoex_disable(sc->sc_ah);
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_btcoex_timer_pause(sc, &sc->btcoex_info);
+ }
+
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
@@ -2140,6 +2171,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);
ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
sc->sc_flags |= SC_OP_INVALID;
@@ -2214,8 +2246,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if ((conf->type == NL80211_IFTYPE_STATION) ||
(conf->type == NL80211_IFTYPE_ADHOC) ||
(conf->type == NL80211_IFTYPE_MESH_POINT)) {
- if (ath9k_hw_phycounters(sc->sc_ah))
- sc->imask |= ATH9K_INT_MIB;
+ sc->imask |= ATH9K_INT_MIB;
sc->imask |= ATH9K_INT_TSFOOR;
}
@@ -2380,6 +2411,7 @@ skip_chan_change:
(FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_CONTROL | \
+ FIF_PSPOLL | \
FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_FCSFAIL)
@@ -2388,8 +2420,7 @@ skip_chan_change:
static void ath9k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count,
- struct dev_mc_list *mclist)
+ u64 multicast)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
@@ -2404,7 +2435,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
ath9k_ps_restore(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
@@ -2712,6 +2743,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
if (ath9k_wiphy_scanning(sc)) {
printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
"same time\n");
@@ -2719,6 +2751,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
* Do not allow the concurrent scanning state for now. This
* could be improved with scanning control moved into ath9k.
*/
+ mutex_unlock(&sc->mutex);
return;
}
@@ -2728,6 +2761,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
spin_unlock_bh(&sc->ani_lock);
+ mutex_unlock(&sc->mutex);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2735,11 +2769,14 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
spin_unlock_bh(&sc->ani_lock);
+ ath_beacon_config(sc, NULL);
+ mutex_unlock(&sc->mutex);
}
struct ieee80211_ops ath9k_ops = {