X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fath9k%2Fmain.c;h=11d7bee2fda059a046492daaf306f3ac63f45768;hb=a8efee4f4740c61fccaf73608df282c4ee24ae86;hp=f05f584ab7bc960f9e8ba5ea29207ec63582bd2c;hpb=0a9b86381c76e9d33a9b6edb66aef32d7a3306e3;p=linux-2.6-omap-h63xx.git diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f05f584ab7b..11d7bee2fda 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -18,11 +18,10 @@ #include #include "core.h" +#include "reg.h" #define ATH_PCI_VERSION "0.1" -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); @@ -39,6 +38,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { 0 } }; +static void ath_detach(struct ath_softc *sc); + static int ath_get_channel(struct ath_softc *sc, struct ieee80211_channel *chan) { @@ -61,24 +62,24 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, switch (chan->band) { case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && (tx_chan_width == ATH9K_HT_MACMODE_20)) chanmode = CHANNEL_G_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_G_HT40MINUS; break; case IEEE80211_BAND_5GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && (tx_chan_width == ATH9K_HT_MACMODE_20)) chanmode = CHANNEL_A_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_A_HT40MINUS; break; @@ -164,7 +165,7 @@ static int ath_key_config(struct ath_softc *sc, if (!sc->sc_vaps[0]) return -EIO; - vif = sc->sc_vaps[0]->av_if_data; + vif = sc->sc_vaps[0]; opmode = vif->type; /* @@ -215,167 +216,57 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) ath_key_reset(sc, key->keyidx, freeslot); } -static void setup_ht_cap(struct ieee80211_ht_info *ht_info) +static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) { #define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ #define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ - ht_info->ht_supported = 1; - ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH - |(u16)IEEE80211_HT_CAP_SM_PS - |(u16)IEEE80211_HT_CAP_SGI_40 - |(u16)IEEE80211_HT_CAP_DSSSCCK40; + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; - /* setup supported mcs set */ - memset(ht_info->supp_mcs_set, 0, 16); - ht_info->supp_mcs_set[0] = 0xff; - ht_info->supp_mcs_set[1] = 0xff; - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; -} - -static int ath_rate2idx(struct ath_softc *sc, int rate) -{ - int i = 0, cur_band, n_rates; - struct ieee80211_hw *hw = sc->hw; - - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; - - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].bitrate == rate) - break; - } - - /* - * NB:mac80211 validates rx rate index against the supported legacy rate - * index only (should be done against ht rates also), return the highest - * legacy rate index for rx rate which does not match any one of the - * supported basic and extended rates to make mac80211 happy. - * The following hack will be cleaned up once the issue with - * the rx rate index validation in mac80211 is fixed. - */ - if (i == n_rates) - return n_rates - 1; - return i; -} - -static void ath9k_rx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - rx_status->mactime = status->tsf; - rx_status->band = curchan->band; - rx_status->freq = curchan->center_freq; - rx_status->noise = sc->sc_ani.sc_noise_floor; - rx_status->signal = rx_status->noise + status->rssi; - rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); - rx_status->antenna = status->antenna; - - /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */ - rx_status->qual = status->rssi * 100 / 64; - - if (status->flags & ATH_RX_MIC_ERROR) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - if (status->flags & ATH_RX_FCS_ERROR) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - - rx_status->flag |= RX_FLAG_TSFT; -} - -static u8 parse_mpdudensity(u8 mpdudensity) -{ - /* - * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": - * 0 for no restriction - * 1 for 1/4 us - * 2 for 1/2 us - * 3 for 1 us - * 4 for 2 us - * 5 for 4 us - * 6 for 8 us - * 7 for 16 us - */ - switch (mpdudensity) { - case 0: - return 0; - case 1: - case 2: - case 3: - /* Our lower layer calculations limit our precision to - 1 microsecond */ - return 1; - case 4: - return 2; - case 5: - return 4; - case 6: - return 8; - case 7: - return 16; - default: - return 0; - } + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.rx_mask[1] = 0xff; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } static void ath9k_ht_conf(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { -#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) struct ath_ht_info *ht_info = &sc->sc_ht_info; - if (bss_conf->assoc_ht) { - ht_info->ext_chan_offset = - bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_SEC_OFFSET; + if (sc->hw->conf.ht.enabled) { + ht_info->ext_chan_offset = bss_conf->ht.secondary_channel_offset; - if (!(bss_conf->ht_conf->cap & - IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_WIDTH)) + if (bss_conf->ht.width_40_ok) ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; else ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); - ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - bss_conf->ht_conf->ampdu_factor); - ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_conf->ampdu_density); - } - -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT } static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_channel *curchan = hw->conf.channel; - struct ath_vap *avp; + struct ath_vap *avp = (void *)vif->drv_priv; int pos; - DECLARE_MAC_BUF(mac); if (bss_conf->assoc) { DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", __func__, bss_conf->aid); - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } - /* New association, store aid */ if (avp->av_opmode == ATH9K_M_STA) { sc->sc_curaid = bss_conf->aid; @@ -394,12 +285,12 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; /* Update chainmask */ - ath_update_chainmask(sc, bss_conf->assoc_ht); + ath_update_chainmask(sc, hw->conf.ht.enabled); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", + "%s: bssid %pM aid 0x%x\n", __func__, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + sc->sc_curbssid, sc->sc_curaid); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", __func__, @@ -412,7 +303,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, return; } - if (hw->conf.ht_conf.ht_supported) + if (hw->conf.ht.enabled) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); else @@ -425,11 +316,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", __func__); - - ath_rate_newstate(sc, avp); - /* Update ratectrl about the new state */ - ath_rc_node_update(hw, avp->rc_node); - /* Start ANI */ mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -456,7 +342,7 @@ void ath_get_beaconconfig(struct ath_softc *sc, } void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an) + struct ath_xmit_status *tx_status) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -466,10 +352,10 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info */ - if (tx_info->driver_data[0] != NULL) - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; + if (tx_info->rate_driver_data[0] != NULL) { + kfree(tx_info->rate_driver_data[0]); + tx_info->rate_driver_data[0] = NULL; + } } if (tx_status->flags & ATH_TX_BAR) { @@ -477,89 +363,14 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_status->flags &= ~ATH_TX_BAR; } - if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - /* Frame was not ACKed, but an ACK was expected */ - tx_info->status.excessive_retries = 1; - } - } else { + if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { /* Frame was ACKed */ tx_info->flags |= IEEE80211_TX_STAT_ACK; } - tx_info->status.retry_count = tx_status->retries; + tx_info->status.rates[0].count = tx_status->retries + 1; ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); -} - -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_node *an = NULL; - struct ieee80211_rx_status rx_status; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - int padsize; - enum ATH_RX_TYPE st; - - /* see if any padding is done by the hw and remove it */ - if (hdrlen & 3) { - padsize = hdrlen % 4; - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && - !(status->flags & ATH_RX_DECRYPT_ERROR)) { - rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) - && !(status->flags & ATH_RX_DECRYPT_ERROR) - && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, sc->sc_keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; - } - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr2); - spin_unlock_bh(&sc->node_lock); - - if (an) { - ath_rx_input(sc, an, - hw->conf.ht_conf.ht_supported, - skb, status, &st); - } - if (!an || (st != ATH_RX_CONSUMED)) - __ieee80211_rx(hw, skb, &rx_status); - - return 0; -} - -int ath_rx_subframe(struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *status) -{ - struct ath_softc *sc = an->an_sc; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_rx_status rx_status; - - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - if (!(status->flags & ATH_RX_DECRYPT_ERROR)) - rx_status.flag |= RX_FLAG_DECRYPTED; - - __ieee80211_rx(hw, skb, &rx_status); - - return 0; } /********************************/ @@ -677,7 +488,8 @@ fail: ath_deinit_leds(sc); } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /*******************/ /* Rfkill */ /*******************/ @@ -878,43 +690,71 @@ static void ath_deinit_rfkill(struct ath_softc *sc) 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 */ + ath_detach(sc); + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(sc->hw); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } + + return 0; +} #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; + int i = 0; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); - /* Deinit LED control */ - ath_deinit_leds(sc); - -#ifdef CONFIG_RFKILL - /* deinit rfkill */ +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif - - /* Unregister hw */ + ath_deinit_leds(sc); ieee80211_unregister_hw(hw); - /* unregister Rate control */ ath_rate_control_unregister(); - /* tx/rx cleanup */ - ath_rx_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, - struct ath_softc *sc) +static int ath_attach(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; int error = 0; @@ -925,50 +765,23 @@ static int ath_attach(u16 devid, if (error != 0) return error; - /* Init nodes */ - - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); - /* get mac address from hardware and set in mac80211 */ SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); - /* 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 (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_info); - - 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_info); - - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; - } + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; - /* FIXME: Have to figure out proper hw init values later */ + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); hw->queues = 4; - hw->ampdu_queues = 1; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vap); /* Register rate control */ hw->rate_control_algorithm = "ath9k_rate_control"; @@ -981,16 +794,27 @@ static int ath_attach(u16 devid, goto bad; } - error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - 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); } - /* Initialize LED control */ - ath_init_leds(sc); + 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]; -#ifdef CONFIG_RFKILL + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto detach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto detach; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* Initialze h/w Rfkill */ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); @@ -1000,15 +824,14 @@ static int ath_attach(u16 devid, goto detach; #endif - /* initialize tx/rx engine */ - - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto detach; + error = ieee80211_register_hw(hw); + if (error != 0) { + ath_rate_control_unregister(); + goto bad; + } - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto detach; + /* Initialize LED control */ + ath_init_leds(sc); return 0; detach: @@ -1026,62 +849,44 @@ static int ath9k_start(struct ieee80211_hw *hw) DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " "initial channel: %d MHz\n", __func__, curchan->center_freq); + memset(&sc->sc_ht_info, 0, sizeof(struct ath_ht_info)); + /* setup initial channel */ pos = ath_get_channel(sc, curchan); if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; + error = -EINVAL; + goto exit; } sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - /* open ath_dev */ error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); if (error) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to complete ath_open\n", __func__); - return error; + goto exit; } -#ifdef CONFIG_RFKILL - /* Start rfkill polling */ - 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; - } - } +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + error = ath_start_rfkill_poll(sc); #endif - ieee80211_wake_queues(hw); - return 0; +exit: + return error; } static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = hw->priv; + struct ath_tx_control txctl; int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* * As a temporary workaround, assign seq# here; this will likely need @@ -1106,45 +911,47 @@ static int ath9k_tx(struct ieee80211_hw *hw, memmove(skb->data, skb->data + padsize, hdrlen); } + /* Check if a tx queue is available */ + + txctl.txq = ath_test_get_txq(sc, skb); + if (!txctl.txq) + goto exit; + DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", __func__, skb); - if (ath_tx_start(sc, skb) != 0) { + if (ath_tx_start(sc, skb, &txctl) != 0) { DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); - dev_kfree_skb_any(skb); - /* FIXME: Check for proper return value from ATH_DEV */ - return 0; + goto exit; } + return 0; +exit: + dev_kfree_skb_any(skb); return 0; } static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - int error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); - error = ath_suspend(sc); - if (error) - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Device is no longer present\n", __func__); + if (sc->sc_flags & SC_OP_INVALID) { + DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__); + return; + } - ieee80211_stop_queues(hw); + ath_stop(sc); -#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 + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); } static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - int error, ic_opmode = 0; + struct ath_vap *avp = (void *)conf->vif->drv_priv; + int ic_opmode = 0; /* Support only vap for now */ @@ -1172,13 +979,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, __func__, ic_opmode); - error = ath_vap_attach(sc, 0, conf->vif, ic_opmode); - if (error) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to attach vap, error: %d\n", - __func__, error); - return error; - } + /* Set the VAP opmode */ + avp->av_opmode = ic_opmode; + avp->av_bslot = -1; + + if (ic_opmode == ATH9K_M_HOSTAP) + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + + sc->sc_vaps[0] = conf->vif; + sc->sc_nvaps++; + + /* Set the device opmode */ + sc->sc_ah->ah_opmode = ic_opmode; if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ @@ -1194,27 +1006,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - struct ath_vap *avp; - int error; + struct ath_vap *avp = (void *)conf->vif->drv_priv; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } - #ifdef CONFIG_SLOW_ANT_DIV ath_slow_ant_div_stop(&sc->sc_antdiv); #endif /* Stop ANI */ del_timer_sync(&sc->sc_ani.timer); - /* Update ratectrl */ - ath_rate_newstate(sc, avp); - /* Reclaim beacon resources */ if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { @@ -1222,29 +1023,26 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_beacon_return(sc, avp); } - /* Set interrupt mask */ - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL); sc->sc_flags &= ~SC_OP_BEACONS; - error = ath_vap_detach(sc, 0); - if (error) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to detach vap, error: %d\n", - __func__, error); + sc->sc_vaps[0] = NULL; + sc->sc_nvaps--; } -static int ath9k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; struct ieee80211_channel *curchan = hw->conf.channel; + struct ieee80211_conf *conf = &hw->conf; int pos; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", __func__, curchan->center_freq); + /* Update chainmask */ + ath_update_chainmask(sc, conf->ht.enabled); + pos = ath_get_channel(sc, curchan); if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); @@ -1255,11 +1053,12 @@ static int ath9k_config(struct ieee80211_hw *hw, (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) + if (sc->sc_curaid && hw->conf.ht.enabled) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); - sc->sc_config.txpowlimit = 2 * conf->power_level; + if (changed & IEEE80211_CONF_CHANGE_POWER) + sc->sc_config.txpowlimit = 2 * conf->power_level; /* set h/w channel */ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) @@ -1275,17 +1074,9 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; + struct ath_vap *avp = (void *)vif->drv_priv; u32 rfilt = 0; int error, i; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return -EINVAL; - } /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ @@ -1303,9 +1094,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - /* Update ratectrl about the new state */ - ath_rate_newstate(sc, avp); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; @@ -1315,27 +1103,10 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->sc_config.ath_aggr_prot = 0; - /* - * Reset our TSF so that its value is lower than the - * beacon that we are trying to catch. - * Only then hw will update its TSF register with the - * new beacon. Reset the TSF before setting the BSSID - * to avoid allowing in any frames that would update - * our TSF only to have us clear it - * immediately thereafter. - */ - ath9k_hw_reset_tsf(sc->sc_ah); - - /* Disable BMISS interrupt when we're not associated */ - ath9k_hw_set_interrupts(sc->sc_ah, - sc->sc_imask & - ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", + "%s: RX filter 0x%x bssid %pM aid 0x%x\n", __func__, rfilt, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + sc->sc_curbssid, sc->sc_curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -1367,7 +1138,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { + if ((avp->av_opmode != ATH9K_M_STA)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, @@ -1422,37 +1193,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; - struct ath_node *an; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, sta->addr); - spin_unlock_irqrestore(&sc->node_lock, flags); switch (cmd) { case STA_NOTIFY_ADD: - spin_lock_irqsave(&sc->node_lock, flags); - if (!an) { - ath_node_attach(sc, sta->addr, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, print_mac(mac, sta->addr)); - } else { - ath_node_get(sc, sta->addr); - } - spin_unlock_irqrestore(&sc->node_lock, flags); + ath_node_attach(sc, sta); break; case STA_NOTIFY_REMOVE: - if (!an) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Removal of a non-existent node\n", - __func__); - else { - ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", - __func__, - print_mac(mac, sta->addr)); - } + ath_node_detach(sc, sta); break; default: break; @@ -1558,9 +1305,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n", - __func__, - bss_conf->assoc_ht); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT\n", + __func__); ath9k_ht_conf(sc, bss_conf); } @@ -1568,7 +1314,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", __func__, bss_conf->assoc); - ath9k_bss_assoc_info(sc, bss_conf); + ath9k_bss_assoc_info(sc, vif, bss_conf); } } @@ -1601,21 +1347,13 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start RX aggregation\n", - __func__); + if (!(sc->sc_flags & SC_OP_RXAGGR)) + ret = -ENOTSUPP; break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, sta->addr, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop RX aggregation\n", - __func__); break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); + ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to start TX aggregation\n", @@ -1624,7 +1362,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta->addr, tid); + ret = ath_tx_aggr_stop(sc, sta, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to stop TX aggregation\n", @@ -1632,6 +1370,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; + case IEEE80211_AMPDU_TX_RESUME: + ath_tx_aggr_resume(sc, sta, tid); + break; default: DPRINTF(sc, ATH_DBG_FATAL, "%s: Unknown AMPDU action\n", __func__); @@ -1654,42 +1395,100 @@ static struct ieee80211_ops ath9k_ops = { .config = ath9k_config, .config_interface = ath9k_config_interface, .configure_filter = ath9k_configure_filter, - .get_stats = NULL, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, - .get_tx_stats = NULL, .bss_info_changed = ath9k_bss_info_changed, - .set_tim = NULL, .set_key = ath9k_set_key, - .hw_scan = NULL, - .get_tkip_seq = NULL, - .set_rts_threshold = NULL, - .set_frag_threshold = NULL, - .set_retry_limit = NULL, .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, - .tx_last_beacon = NULL, .ampdu_action = ath9k_ampdu_action, .set_frag_threshold = ath9k_no_fragmentation, }; +static struct { + u32 version; + const char * name; +} ath_mac_bb_names[] = { + { AR_SREV_VERSION_5416_PCI, "5416" }, + { AR_SREV_VERSION_5416_PCIE, "5418" }, + { AR_SREV_VERSION_9100, "9100" }, + { AR_SREV_VERSION_9160, "9160" }, + { AR_SREV_VERSION_9280, "9280" }, + { AR_SREV_VERSION_9285, "9285" } +}; + +static struct { + u16 version; + const char * name; +} ath_rf_names[] = { + { 0, "5133" }, + { AR_RAD5133_SREV_MAJOR, "5133" }, + { AR_RAD5122_SREV_MAJOR, "5122" }, + { AR_RAD2133_SREV_MAJOR, "2133" }, + { AR_RAD2122_SREV_MAJOR, "2122" } +}; + +/* + * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. + */ + +static const char * +ath_mac_bb_name(u32 mac_bb_version) +{ + int i; + + for (i=0; iflags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -1778,11 +1567,15 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad4; } - athname = ath9k_hw_probe(id->vendor, id->device); - - printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n", + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x " + "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - athname ? athname : "Atheros ???", + ath_mac_bb_name(ah->ah_macVersion), + ah->ah_macRev, + ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->ah_phyRev, (unsigned long)mem, pdev->irq); return 0; @@ -1803,17 +1596,10 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); 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); - + if (pdev->irq) + free_irq(pdev->irq, sc); pci_iounmap(pdev, sc->mem); pci_release_region(pdev, 0); pci_disable_device(pdev); @@ -1829,7 +1615,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif @@ -1866,7 +1652,7 @@ static int ath_pci_resume(struct pci_dev *pdev) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* * check the h/w rfkill state on resume * and start the rfkill poll timer