From: Bob Copeland Date: Fri, 17 Sep 2010 03:45:07 +0000 (+0900) Subject: ath5k: reorder base.c to remove fwd decls X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=8a63facc376a7b8bb2b64c0ffbdb0949d1d6c71c;p=linux-beck.git ath5k: reorder base.c to remove fwd decls This change reorganizes the main ath5k file in order to re-group related functions and remove most of the forward declarations (from 61 down to 3). This is, unfortunately, a lot of churn, but there should be no functional changes. Signed-off-by: Bob Copeland Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 0709bb091b2f..4a07fb89021e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -70,11 +70,6 @@ static int modparam_all_channels; module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); - -/******************\ -* Internal defines * -\******************/ - /* Module info */ MODULE_AUTHOR("Jiri Slaby"); MODULE_AUTHOR("Nick Kossifidis"); @@ -83,6 +78,10 @@ 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_beacon_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); /* Known PCI ids */ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = { @@ -190,129 +189,6 @@ static const struct ieee80211_rate ath5k_rates[] = { /* XR missing */ }; -/* - * Prototypes - PCI stack related functions - */ -static int __devinit ath5k_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id); -static void __devexit ath5k_pci_remove(struct pci_dev *pdev); -#ifdef CONFIG_PM_SLEEP -static int ath5k_pci_suspend(struct device *dev); -static int ath5k_pci_resume(struct device *dev); - -static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); -#define ATH5K_PM_OPS (&ath5k_pm_ops) -#else -#define ATH5K_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - -static struct pci_driver ath5k_pci_driver = { - .name = KBUILD_MODNAME, - .id_table = ath5k_pci_id_table, - .probe = ath5k_pci_probe, - .remove = __devexit_p(ath5k_pci_remove), - .driver.pm = ATH5K_PM_OPS, -}; - - - -/* - * Prototypes - MAC 802.11 stack related functions - */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath5k_txq *txq); -static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan); -static int ath5k_start(struct ieee80211_hw *hw); -static void ath5k_stop(struct ieee80211_hw *hw); -static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -static int ath5k_config(struct ieee80211_hw *hw, u32 changed); -static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list); -static void ath5k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - u64 multicast); -static int ath5k_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); -static int ath5k_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats); -static int ath5k_get_survey(struct ieee80211_hw *hw, - int idx, struct survey_info *survey); -static u64 ath5k_get_tsf(struct ieee80211_hw *hw); -static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); -static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -static void ath5k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes); -static void ath5k_sw_scan_start(struct ieee80211_hw *hw); -static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); -static void ath5k_set_coverage_class(struct ieee80211_hw *hw, - u8 coverage_class); - -static const struct ieee80211_ops ath5k_hw_ops = { - .tx = ath5k_tx, - .start = ath5k_start, - .stop = ath5k_stop, - .add_interface = ath5k_add_interface, - .remove_interface = ath5k_remove_interface, - .config = ath5k_config, - .prepare_multicast = ath5k_prepare_multicast, - .configure_filter = ath5k_configure_filter, - .set_key = ath5k_set_key, - .get_stats = ath5k_get_stats, - .get_survey = ath5k_get_survey, - .conf_tx = NULL, - .get_tsf = ath5k_get_tsf, - .set_tsf = ath5k_set_tsf, - .reset_tsf = ath5k_reset_tsf, - .bss_info_changed = ath5k_bss_info_changed, - .sw_scan_start = ath5k_sw_scan_start, - .sw_scan_complete = ath5k_sw_scan_complete, - .set_coverage_class = ath5k_set_coverage_class, -}; - -/* - * Prototypes - Internal functions - */ -/* Attach detach */ -static int ath5k_attach(struct pci_dev *pdev, - struct ieee80211_hw *hw); -static void ath5k_detach(struct pci_dev *pdev, - struct ieee80211_hw *hw); -/* Channel/mode setup */ -static inline short ath5k_ieee2mhz(short chan); -static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max); -static int ath5k_setup_bands(struct ieee80211_hw *hw); -static int ath5k_chan_set(struct ath5k_softc *sc, - struct ieee80211_channel *chan); -static void ath5k_setcurmode(struct ath5k_softc *sc, - unsigned int mode); -static void ath5k_mode_setup(struct ath5k_softc *sc); - -/* Descriptor setup */ -static int ath5k_desc_alloc(struct ath5k_softc *sc, - struct pci_dev *pdev); -static void ath5k_desc_free(struct ath5k_softc *sc, - struct pci_dev *pdev); -/* Buffers setup */ -static int ath5k_rxbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ath5k_txq *txq, int padsize); - static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -345,35 +221,6 @@ static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc, } -/* Queues setup */ -static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc, - int qtype, int subtype); -static int ath5k_beaconq_setup(struct ath5k_hw *ah); -static int ath5k_beaconq_config(struct ath5k_softc *sc); -static void ath5k_txq_drainq(struct ath5k_softc *sc, - struct ath5k_txq *txq); -static void ath5k_txq_cleanup(struct ath5k_softc *sc); -static void ath5k_txq_release(struct ath5k_softc *sc); -/* Rx handling */ -static int ath5k_rx_start(struct ath5k_softc *sc); -static void ath5k_rx_stop(struct ath5k_softc *sc); -static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, - struct sk_buff *skb, - struct ath5k_rx_status *rs); -static void ath5k_tasklet_rx(unsigned long data); -/* Tx handling */ -static void ath5k_tx_processq(struct ath5k_softc *sc, - struct ath5k_txq *txq); -static void ath5k_tasklet_tx(unsigned long data); -/* Beacon handling */ -static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -static void ath5k_beacon_send(struct ath5k_softc *sc); -static void ath5k_beacon_config(struct ath5k_softc *sc); -static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); -static void ath5k_tasklet_beacon(unsigned long data); -static void ath5k_tasklet_ani(unsigned long data); - static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) { u64 tsf = ath5k_hw_get_tsf64(ah); @@ -384,50 +231,6 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) return (tsf & ~0x7fff) | rstamp; } -/* Interrupt handling */ -static int ath5k_init(struct ath5k_softc *sc); -static int ath5k_stop_locked(struct ath5k_softc *sc); -static int ath5k_stop_hw(struct ath5k_softc *sc); -static irqreturn_t ath5k_intr(int irq, void *dev_id); -static void ath5k_reset_work(struct work_struct *work); - -static void ath5k_tasklet_calibrate(unsigned long data); - -/* - * Module init/exit functions - */ -static int __init -init_ath5k_pci(void) -{ - int ret; - - ath5k_debug_init(); - - ret = pci_register_driver(&ath5k_pci_driver); - if (ret) { - printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); - return ret; - } - - return 0; -} - -static void __exit -exit_ath5k_pci(void) -{ - pci_unregister_driver(&ath5k_pci_driver); - - ath5k_debug_finish(); -} - -module_init(init_ath5k_pci); -module_exit(exit_ath5k_pci); - - -/********************\ -* PCI Initialization * -\********************/ - static const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) { @@ -466,1695 +269,1286 @@ static const struct ath_ops ath5k_common_ops = { .write = ath5k_iowrite32, }; -static int __devinit -ath5k_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +/***********************\ +* Driver Initialization * +\***********************/ + +static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { - void __iomem *mem; - struct ath5k_softc *sc; - struct ath_common *common; - struct ieee80211_hw *hw; - int ret; - u8 csz; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath5k_softc *sc = hw->priv; + struct ath_regulatory *regulatory = ath5k_hw_regulatory(sc->ah); - /* - * L0s needs to be disabled on all ath5k cards. - * - * For distributions shipping with CONFIG_PCIEASPM (this will be enabled - * by default in the future in 2.6.36) this will also mean both L1 and - * L0s will be disabled when a pre 1.1 PCIe device is detected. We do - * know L1 works correctly even for all ath5k pre 1.1 PCIe devices - * though but cannot currently undue the effect of a blacklist, for - * details you can read pcie_aspm_sanity_check() and see how it adjusts - * the device link capability. - * - * It may be possible in the future to implement some PCI API to allow - * drivers to override blacklists for pre 1.1 PCIe but for now it is - * best to accept that both L0s and L1 will be disabled completely for - * distributions shipping with CONFIG_PCIEASPM rather than having this - * issue present. Motivation for adding this new API will be to help - * with power consumption for some of these devices. - */ - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); + return ath_reg_notifier_apply(wiphy, request, regulatory); +} - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "can't enable device\n"); - goto err; - } +/********************\ +* Channel/mode setup * +\********************/ - /* XXX 32-bit addressing only */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "32-bit DMA not available\n"); - goto err_dis; - } +/* + * Convert IEEE channel number to MHz frequency. + */ +static inline short +ath5k_ieee2mhz(short chan) +{ + if (chan <= 14 || chan >= 27) + return ieee80211chan2mhz(chan); + else + return 2212 + chan * 20; +} - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); - if (csz == 0) { - /* - * Linux 2.4.18 (at least) writes the cache line size - * register as a 16-bit wide register which is wrong. - * We must have this setup properly for rx buffer - * DMA to work so force a reasonable value here if it - * comes up zero. - */ - csz = L1_CACHE_BYTES >> 2; - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); - } - /* - * The default setting of latency timer yields poor results, - * set it to the value used by other systems. It may be worth - * tweaking this setting more. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); +/* + * Returns true for the channel numbers used without all_channels modparam. + */ +static bool ath5k_is_standard_channel(short chan) +{ + return ((chan <= 14) || + /* UNII 1,2 */ + ((chan & 3) == 0 && chan >= 36 && chan <= 64) || + /* midband */ + ((chan & 3) == 0 && chan >= 100 && chan <= 140) || + /* UNII-3 */ + ((chan & 3) == 1 && chan >= 149 && chan <= 165)); +} - /* Enable bus mastering */ - pci_set_master(pdev); +static unsigned int +ath5k_copy_channels(struct ath5k_hw *ah, + struct ieee80211_channel *channels, + unsigned int mode, + unsigned int max) +{ + unsigned int i, count, size, chfreq, freq, ch; - /* - * Disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state. - */ - pci_write_config_byte(pdev, 0x41, 0); + if (!test_bit(mode, ah->ah_modes)) + return 0; - ret = pci_request_region(pdev, 0, "ath5k"); - if (ret) { - dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); - goto err_dis; + switch (mode) { + case AR5K_MODE_11A: + case AR5K_MODE_11A_TURBO: + /* 1..220, but 2GHz frequencies are filtered by check_channel */ + size = 220 ; + chfreq = CHANNEL_5GHZ; + break; + case AR5K_MODE_11B: + case AR5K_MODE_11G: + case AR5K_MODE_11G_TURBO: + size = 26; + chfreq = CHANNEL_2GHZ; + break; + default: + ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); + return 0; } - mem = pci_iomap(pdev, 0, 0); - if (!mem) { - dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; - ret = -EIO; - goto err_reg; - } + for (i = 0, count = 0; i < size && max > 0; i++) { + ch = i + 1 ; + freq = ath5k_ieee2mhz(ch); - /* - * Allocate hw (mac80211 main struct) - * and hw->priv (driver private data) - */ - hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); - if (hw == NULL) { - dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); - ret = -ENOMEM; - goto err_map; - } - - dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); - - /* Initialize driver private data */ - SET_IEEE80211_DEV(hw, &pdev->dev); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM; + /* Check if channel is supported by the chipset */ + if (!ath5k_channel_ok(ah, freq, chfreq)) + continue; - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); + if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) + continue; - hw->extra_tx_headroom = 2; - hw->channel_change_time = 5000; - sc = hw->priv; - sc->hw = hw; - sc->pdev = pdev; + /* Write channel info and increment counter */ + channels[count].center_freq = freq; + channels[count].band = (chfreq == CHANNEL_2GHZ) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + switch (mode) { + case AR5K_MODE_11A: + case AR5K_MODE_11G: + channels[count].hw_value = chfreq | CHANNEL_OFDM; + break; + case AR5K_MODE_11A_TURBO: + case AR5K_MODE_11G_TURBO: + channels[count].hw_value = chfreq | + CHANNEL_OFDM | CHANNEL_TURBO; + break; + case AR5K_MODE_11B: + channels[count].hw_value = CHANNEL_B; + } - ath5k_debug_init_device(sc); + count++; + max--; + } - /* - * Mark the device as detached to avoid processing - * interrupts until setup is complete. - */ - __set_bit(ATH_STAT_INVALID, sc->status); + return count; +} - sc->iobase = mem; /* So we can unmap it on detach */ - sc->opmode = NL80211_IFTYPE_STATION; - sc->bintval = 1000; - mutex_init(&sc->lock); - spin_lock_init(&sc->rxbuflock); - spin_lock_init(&sc->txbuflock); - spin_lock_init(&sc->block); +static void +ath5k_setup_rate_idx(struct ath5k_softc *sc, struct ieee80211_supported_band *b) +{ + u8 i; - /* Set private data */ - pci_set_drvdata(pdev, sc); + for (i = 0; i < AR5K_MAX_RATES; i++) + sc->rate_idx[b->band][i] = -1; - /* Setup interrupt handler */ - ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); - if (ret) { - ATH5K_ERR(sc, "request_irq failed\n"); - goto err_free; + for (i = 0; i < b->n_bitrates; i++) { + sc->rate_idx[b->band][b->bitrates[i].hw_value] = i; + if (b->bitrates[i].hw_value_short) + sc->rate_idx[b->band][b->bitrates[i].hw_value_short] = i; } +} - /* If we passed the test, malloc an ath5k_hw struct */ - sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); - if (!sc->ah) { - ret = -ENOMEM; - ATH5K_ERR(sc, "out of memory\n"); - goto err_irq; - } +static int +ath5k_setup_bands(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ieee80211_supported_band *sband; + int max_c, count_c = 0; + int i; - sc->ah->ah_sc = sc; - sc->ah->ah_iobase = sc->iobase; - common = ath5k_hw_common(sc->ah); - common->ops = &ath5k_common_ops; - common->ah = sc->ah; - common->hw = hw; - common->cachelsz = csz << 2; /* convert to bytes */ + BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); + max_c = ARRAY_SIZE(sc->channels); - /* Initialize device */ - ret = ath5k_hw_attach(sc); - if (ret) { - goto err_free_ah; - } + /* 2GHz band */ + sband = &sc->sbands[IEEE80211_BAND_2GHZ]; + sband->band = IEEE80211_BAND_2GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0]; - /* set up multi-rate retry capabilities */ - if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_rates = 4; - hw->max_rate_tries = 11; - } + if (test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { + /* G mode */ + memcpy(sband->bitrates, &ath5k_rates[0], + sizeof(struct ieee80211_rate) * 12); + sband->n_bitrates = 12; - /* Finish private driver data initialization */ - ret = ath5k_attach(pdev, hw); - if (ret) - goto err_ah; + sband->channels = sc->channels; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11G, max_c); - ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", - ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev), - sc->ah->ah_mac_srev, - sc->ah->ah_phy_revision); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + count_c = sband->n_channels; + max_c -= count_c; + } else if (test_bit(AR5K_MODE_11B, sc->ah->ah_capabilities.cap_mode)) { + /* B mode */ + memcpy(sband->bitrates, &ath5k_rates[0], + sizeof(struct ieee80211_rate) * 4); + sband->n_bitrates = 4; - if (!sc->ah->ah_single_chip) { - /* Single chip radio (!RF5111) */ - if (sc->ah->ah_radio_5ghz_revision && - !sc->ah->ah_radio_2ghz_revision) { - /* No 5GHz support -> report 2GHz radio */ - if (!test_bit(AR5K_MODE_11A, - sc->ah->ah_capabilities.cap_mode)) { - ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* No 2GHz support (5110 and some - * 5Ghz only cards) -> report 5Ghz radio */ - } else if (!test_bit(AR5K_MODE_11B, - sc->ah->ah_capabilities.cap_mode)) { - ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* Multiband radio */ - } else { - ATH5K_INFO(sc, "RF%s multiband radio found" - " (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); + /* 5211 only supports B rates and uses 4bit rate codes + * (e.g normally we have 0x1B for 1M, but on 5211 we have 0x0B) + * fix them up here: + */ + if (ah->ah_version == AR5K_AR5211) { + for (i = 0; i < 4; i++) { + sband->bitrates[i].hw_value = + sband->bitrates[i].hw_value & 0xF; + sband->bitrates[i].hw_value_short = + sband->bitrates[i].hw_value_short & 0xF; } } - /* Multi chip radio (RF5111 - RF2111) -> - * report both 2GHz/5GHz radios */ - else if (sc->ah->ah_radio_5ghz_revision && - sc->ah->ah_radio_2ghz_revision){ - ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_2ghz_revision), - sc->ah->ah_radio_2ghz_revision); - } - } + sband->channels = sc->channels; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11B, max_c); - /* ready to process interrupts */ - __clear_bit(ATH_STAT_INVALID, sc->status); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + count_c = sband->n_channels; + max_c -= count_c; + } + ath5k_setup_rate_idx(sc, sband); - return 0; -err_ah: - ath5k_hw_detach(sc->ah); -err_free_ah: - kfree(sc->ah); -err_irq: - free_irq(pdev->irq, sc); -err_free: - ieee80211_free_hw(hw); -err_map: - pci_iounmap(pdev, mem); -err_reg: - pci_release_region(pdev, 0); -err_dis: - pci_disable_device(pdev); -err: - return ret; -} + /* 5GHz band, A mode */ + if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { + sband = &sc->sbands[IEEE80211_BAND_5GHZ]; + sband->band = IEEE80211_BAND_5GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0]; -static void __devexit -ath5k_pci_remove(struct pci_dev *pdev) -{ - struct ath5k_softc *sc = pci_get_drvdata(pdev); + memcpy(sband->bitrates, &ath5k_rates[4], + sizeof(struct ieee80211_rate) * 8); + sband->n_bitrates = 8; - ath5k_debug_finish_device(sc); - ath5k_detach(pdev, sc->hw); - ath5k_hw_detach(sc->ah); - kfree(sc->ah); - free_irq(pdev->irq, sc); - pci_iounmap(pdev, sc->iobase); - pci_release_region(pdev, 0); - pci_disable_device(pdev); - ieee80211_free_hw(sc->hw); -} + sband->channels = &sc->channels[count_c]; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11A, max_c); -#ifdef CONFIG_PM_SLEEP -static int ath5k_pci_suspend(struct device *dev) -{ - struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } + ath5k_setup_rate_idx(sc, sband); + + ath5k_debug_dump_bands(sc); - ath5k_led_off(sc); return 0; } -static int ath5k_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct ath5k_softc *sc = pci_get_drvdata(pdev); - +/* + * Set/change channels. We always reset the chip. + * To accomplish this we must first cleanup any pending DMA, + * then restart stuff after a la ath5k_init. + * + * Called with sc->lock. + */ +static int +ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "channel set, resetting (%u -> %u MHz)\n", + sc->curchan->center_freq, chan->center_freq); + /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. */ - pci_write_config_byte(pdev, 0x41, 0); - - ath5k_led_enable(sc); - return 0; + return ath5k_reset(sc, chan); } -#endif /* CONFIG_PM_SLEEP */ - - -/***********************\ -* Driver Initialization * -\***********************/ -static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +static void +ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath5k_softc *sc = hw->priv; - struct ath_regulatory *regulatory = ath5k_hw_regulatory(sc->ah); + sc->curmode = mode; - return ath_reg_notifier_apply(wiphy, request, regulatory); + if (mode == AR5K_MODE_11A) { + sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; + } else { + sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; + } } -static int -ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) +static void +ath5k_mode_setup(struct ath5k_softc *sc) { - struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); - u8 mac[ETH_ALEN] = {}; - int ret; + u32 rfilt; - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); + /* configure rx filter */ + rfilt = sc->filter_flags; + ath5k_hw_set_rx_filter(ah, rfilt); - /* - * Check if the MAC has multi-rate retry support. - * We do this by trying to setup a fake extended - * descriptor. MACs that don't have support will - * return false w/o doing anything. MACs that do - * support it will return true w/o doing anything. - */ - ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + if (ath5k_hw_hasbssidmask(ah)) + ath5k_hw_set_bssid_mask(ah, sc->bssidmask); - if (ret < 0) - goto err; - if (ret > 0) - __set_bit(ATH_STAT_MRRETRY, sc->status); + /* configure operational mode */ + ath5k_hw_set_opmode(ah, sc->opmode); - /* - * Collect the channel list. The 802.11 layer - * is resposible for filtering this list based - * on settings like the phy mode and regulatory - * domain restrictions. - */ - ret = ath5k_setup_bands(hw); - if (ret) { - ATH5K_ERR(sc, "can't get channels\n"); - goto err; - } + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); +} - /* NB: setup here so ath5k_rate_update is happy */ - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - ath5k_setcurmode(sc, AR5K_MODE_11A); - else - ath5k_setcurmode(sc, AR5K_MODE_11B); +static inline int +ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) +{ + int rix; - /* - * Allocate tx+rx descriptors and populate the lists. - */ - ret = ath5k_desc_alloc(sc, pdev); - if (ret) { - ATH5K_ERR(sc, "can't allocate descriptors\n"); - goto err; - } + /* return base rate on errors */ + if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, + "hw_rix out of bounds: %x\n", hw_rix)) + return 0; + + rix = sc->rate_idx[sc->curband->band][hw_rix]; + if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) + rix = 0; + + return rix; +} + +/***************\ +* Buffers setup * +\***************/ + +static +struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) +{ + struct ath_common *common = ath5k_hw_common(sc->ah); + struct sk_buff *skb; /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that hw functions handle resetting - * these queues at the needed time. + * Allocate buffer with headroom_needed space for the + * fake physical layer header at the start. */ - ret = ath5k_beaconq_setup(ah); - if (ret < 0) { - ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); - goto err_desc; - } - sc->bhalq = ret; - sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); - if (IS_ERR(sc->cabq)) { - ATH5K_ERR(sc, "can't setup cab queue\n"); - ret = PTR_ERR(sc->cabq); - goto err_bhal; - } + skb = ath_rxbuf_alloc(common, + common->rx_bufsize, + GFP_ATOMIC); - sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); - if (IS_ERR(sc->txq)) { - ATH5K_ERR(sc, "can't setup xmit queue\n"); - ret = PTR_ERR(sc->txq); - goto err_queues; + if (!skb) { + ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", + common->rx_bufsize); + return NULL; } - tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); - tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); - tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); - tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); - tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); - - INIT_WORK(&sc->reset_work, ath5k_reset_work); - - ret = ath5k_eeprom_read_mac(ah, mac); - if (ret) { - ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", - sc->pdev->device); - goto err_queues; + *skb_addr = pci_map_single(sc->pdev, + skb->data, common->rx_bufsize, + PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { + ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); + dev_kfree_skb(skb); + return NULL; } + return skb; +} - SET_IEEE80211_PERM_ADDR(hw, mac); - /* All MAC address bits matter for ACKs */ - memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); +static int +ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +{ + struct ath5k_hw *ah = sc->ah; + struct sk_buff *skb = bf->skb; + struct ath5k_desc *ds; + int ret; - regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; - ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); - if (ret) { - ATH5K_ERR(sc, "can't initialize regulatory system\n"); - goto err_queues; + if (!skb) { + skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); + if (!skb) + return -ENOMEM; + bf->skb = skb; } - ret = ieee80211_register_hw(hw); + /* + * Setup descriptors. For receive we always terminate + * the descriptor list with a self-linked entry so we'll + * not get overrun under high load (as can happen with a + * 5212 when ANI processing enables PHY error frames). + * + * To ensure the last descriptor is self-linked we create + * each descriptor as self-linked and add it to the end. As + * each additional descriptor is added the previous self-linked + * entry is "fixed" naturally. This should be safe even + * if DMA is happening. When processing RX interrupts we + * never remove/process the last, self-linked, entry on the + * descriptor list. This ensures the hardware always has + * someplace to write a new frame. + */ + ds = bf->desc; + ds->ds_link = bf->daddr; /* link to self */ + ds->ds_data = bf->skbaddr; + ret = ath5k_hw_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0); if (ret) { - ATH5K_ERR(sc, "can't register ieee80211 hw\n"); - goto err_queues; + ATH5K_ERR(sc, "%s: could not setup RX desc\n", __func__); + return ret; } - if (!ath_is_world_regd(regulatory)) - regulatory_hint(hw->wiphy, regulatory->alpha2); - - ath5k_init_leds(sc); - - ath5k_sysfs_register(sc); - + if (sc->rxlink != NULL) + *sc->rxlink = bf->daddr; + sc->rxlink = &ds->ds_link; return 0; -err_queues: - ath5k_txq_release(sc); -err_bhal: - ath5k_hw_release_tx_queue(ah, sc->bhalq); -err_desc: - ath5k_desc_free(sc, pdev); -err: - return ret; } -static void -ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) +static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) { - struct ath5k_softc *sc = hw->priv; + struct ieee80211_hdr *hdr; + enum ath5k_pkt_type htype; + __le16 fc; - /* - * NB: the order of these is important: - * o call the 802.11 layer before detaching ath5k_hw to - * ensure callbacks into the driver to delete global - * key cache entries can be handled - * o reclaim the tx queue data structures after calling - * the 802.11 layer as we'll get called back to reclaim - * node state and potentially want to use them - * o to cleanup the tx queues the hal is called, so detach - * it last - * XXX: ??? detach ath5k_hw ??? - * Other than that, it's straightforward... - */ - ieee80211_unregister_hw(hw); - ath5k_desc_free(sc, pdev); - ath5k_txq_release(sc); - ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); - ath5k_unregister_leds(sc); - - ath5k_sysfs_unregister(sc); - /* - * NB: can't reclaim these until after ieee80211_ifdetach - * returns because we'll get called back to reclaim node - * state and potentially want to use them. - */ -} - - - - -/********************\ -* Channel/mode setup * -\********************/ + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; -/* - * Convert IEEE channel number to MHz frequency. - */ -static inline short -ath5k_ieee2mhz(short chan) -{ - if (chan <= 14 || chan >= 27) - return ieee80211chan2mhz(chan); + if (ieee80211_is_beacon(fc)) + htype = AR5K_PKT_TYPE_BEACON; + else if (ieee80211_is_probe_resp(fc)) + htype = AR5K_PKT_TYPE_PROBE_RESP; + else if (ieee80211_is_atim(fc)) + htype = AR5K_PKT_TYPE_ATIM; + else if (ieee80211_is_pspoll(fc)) + htype = AR5K_PKT_TYPE_PSPOLL; else - return 2212 + chan * 20; -} + htype = AR5K_PKT_TYPE_NORMAL; -/* - * Returns true for the channel numbers used without all_channels modparam. - */ -static bool ath5k_is_standard_channel(short chan) -{ - return ((chan <= 14) || - /* UNII 1,2 */ - ((chan & 3) == 0 && chan >= 36 && chan <= 64) || - /* midband */ - ((chan & 3) == 0 && chan >= 100 && chan <= 140) || - /* UNII-3 */ - ((chan & 3) == 1 && chan >= 149 && chan <= 165)); + return htype; } -static unsigned int -ath5k_copy_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max) +static int +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ath5k_txq *txq, int padsize) { - unsigned int i, count, size, chfreq, freq, ch; + struct ath5k_hw *ah = sc->ah; + struct ath5k_desc *ds = bf->desc; + struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; + struct ieee80211_rate *rate; + unsigned int mrr_rate[3], mrr_tries[3]; + int i, ret; + u16 hw_rate; + u16 cts_rate = 0; + u16 duration = 0; + u8 rc_flags; - if (!test_bit(mode, ah->ah_modes)) - return 0; + flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - switch (mode) { - case AR5K_MODE_11A: - case AR5K_MODE_11A_TURBO: - /* 1..220, but 2GHz frequencies are filtered by check_channel */ - size = 220 ; - chfreq = CHANNEL_5GHZ; - break; - case AR5K_MODE_11B: - case AR5K_MODE_11G: - case AR5K_MODE_11G_TURBO: - size = 26; - chfreq = CHANNEL_2GHZ; - break; - default: - ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); - return 0; - } + /* XXX endianness */ + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); - for (i = 0, count = 0; i < size && max > 0; i++) { - ch = i + 1 ; - freq = ath5k_ieee2mhz(ch); + rate = ieee80211_get_tx_rate(sc->hw, info); - /* Check if channel is supported by the chipset */ - if (!ath5k_channel_ok(ah, freq, chfreq)) - continue; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= AR5K_TXDESC_NOACK; - if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) - continue; + rc_flags = info->control.rates[0].flags; + hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? + rate->hw_value_short : rate->hw_value; - /* Write channel info and increment counter */ - channels[count].center_freq = freq; - channels[count].band = (chfreq == CHANNEL_2GHZ) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - switch (mode) { - case AR5K_MODE_11A: - case AR5K_MODE_11G: - channels[count].hw_value = chfreq | CHANNEL_OFDM; - break; - case AR5K_MODE_11A_TURBO: - case AR5K_MODE_11G_TURBO: - channels[count].hw_value = chfreq | - CHANNEL_OFDM | CHANNEL_TURBO; + pktlen = skb->len; + + /* FIXME: If we are in g mode and rate is a CCK rate + * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta + * from tx power (value is in dB units already) */ + if (info->control.hw_key) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.hw_key->icv_len; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + flags |= AR5K_TXDESC_RTSENA; + cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; + duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, + sc->vif, pktlen, info)); + } + if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + flags |= AR5K_TXDESC_CTSENA; + cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; + duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, + sc->vif, pktlen, info)); + } + ret = ah->ah_setup_tx_desc(ah, ds, pktlen, + ieee80211_get_hdrlen_from_skb(skb), padsize, + get_hw_packet_type(skb), + (sc->power_level * 2), + hw_rate, + info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, + cts_rate, duration); + if (ret) + goto err_unmap; + + memset(mrr_rate, 0, sizeof(mrr_rate)); + memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i < 3; i++) { + rate = ieee80211_get_alt_retry_rate(sc->hw, info, i); + if (!rate) break; - case AR5K_MODE_11B: - channels[count].hw_value = CHANNEL_B; - } - count++; - max--; + mrr_rate[i] = rate->hw_value; + mrr_tries[i] = info->control.rates[i + 1].count; } - return count; -} + ath5k_hw_setup_mrr_tx_desc(ah, ds, + mrr_rate[0], mrr_tries[0], + mrr_rate[1], mrr_tries[1], + mrr_rate[2], mrr_tries[2]); -static void -ath5k_setup_rate_idx(struct ath5k_softc *sc, struct ieee80211_supported_band *b) -{ - u8 i; + ds->ds_link = 0; + ds->ds_data = bf->skbaddr; - for (i = 0; i < AR5K_MAX_RATES; i++) - sc->rate_idx[b->band][i] = -1; + spin_lock_bh(&txq->lock); + list_add_tail(&bf->list, &txq->q); + if (txq->link == NULL) /* is this first packet? */ + ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); + else /* no, so only link it */ + *txq->link = bf->daddr; - for (i = 0; i < b->n_bitrates; i++) { - sc->rate_idx[b->band][b->bitrates[i].hw_value] = i; - if (b->bitrates[i].hw_value_short) - sc->rate_idx[b->band][b->bitrates[i].hw_value_short] = i; - } + txq->link = &ds->ds_link; + ath5k_hw_start_tx_dma(ah, txq->qnum); + mmiowb(); + spin_unlock_bh(&txq->lock); + + return 0; +err_unmap: + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); + return ret; } +/*******************\ +* Descriptors setup * +\*******************/ + static int -ath5k_setup_bands(struct ieee80211_hw *hw) +ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) { - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - struct ieee80211_supported_band *sband; - int max_c, count_c = 0; - int i; - - BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); - max_c = ARRAY_SIZE(sc->channels); + struct ath5k_desc *ds; + struct ath5k_buf *bf; + dma_addr_t da; + unsigned int i; + int ret; - /* 2GHz band */ - sband = &sc->sbands[IEEE80211_BAND_2GHZ]; - sband->band = IEEE80211_BAND_2GHZ; - sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0]; + /* allocate descriptors */ + sc->desc_len = sizeof(struct ath5k_desc) * + (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); + sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); + if (sc->desc == NULL) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + ret = -ENOMEM; + goto err; + } + ds = sc->desc; + da = sc->desc_daddr; + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", + ds, sc->desc_len, (unsigned long long)sc->desc_daddr); - if (test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { - /* G mode */ - memcpy(sband->bitrates, &ath5k_rates[0], - sizeof(struct ieee80211_rate) * 12); - sband->n_bitrates = 12; + bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, + sizeof(struct ath5k_buf), GFP_KERNEL); + if (bf == NULL) { + ATH5K_ERR(sc, "can't allocate bufptr\n"); + ret = -ENOMEM; + goto err_free; + } + sc->bufptr = bf; - sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, - AR5K_MODE_11G, max_c); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; - count_c = sband->n_channels; - max_c -= count_c; - } else if (test_bit(AR5K_MODE_11B, sc->ah->ah_capabilities.cap_mode)) { - /* B mode */ - memcpy(sband->bitrates, &ath5k_rates[0], - sizeof(struct ieee80211_rate) * 4); - sband->n_bitrates = 4; - - /* 5211 only supports B rates and uses 4bit rate codes - * (e.g normally we have 0x1B for 1M, but on 5211 we have 0x0B) - * fix them up here: - */ - if (ah->ah_version == AR5K_AR5211) { - for (i = 0; i < 4; i++) { - sband->bitrates[i].hw_value = - sband->bitrates[i].hw_value & 0xF; - sband->bitrates[i].hw_value_short = - sband->bitrates[i].hw_value_short & 0xF; - } - } - - sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, - AR5K_MODE_11B, max_c); + INIT_LIST_HEAD(&sc->rxbuf); + for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->rxbuf); + } - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; - count_c = sband->n_channels; - max_c -= count_c; + INIT_LIST_HEAD(&sc->txbuf); + sc->txbuf_len = ATH_TXBUF; + for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, + da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->txbuf); } - ath5k_setup_rate_idx(sc, sband); - /* 5GHz band, A mode */ - if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { - sband = &sc->sbands[IEEE80211_BAND_5GHZ]; - sband->band = IEEE80211_BAND_5GHZ; - sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0]; + /* beacon buffer */ + bf->desc = ds; + bf->daddr = da; + sc->bbuf = bf; - memcpy(sband->bitrates, &ath5k_rates[4], - sizeof(struct ieee80211_rate) * 8); - sband->n_bitrates = 8; + return 0; +err_free: + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); +err: + sc->desc = NULL; + return ret; +} - sband->channels = &sc->channels[count_c]; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, - AR5K_MODE_11A, max_c); +static void +ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) +{ + struct ath5k_buf *bf; - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; - } - ath5k_setup_rate_idx(sc, sband); + ath5k_txbuf_free_skb(sc, sc->bbuf); + list_for_each_entry(bf, &sc->txbuf, list) + ath5k_txbuf_free_skb(sc, bf); + list_for_each_entry(bf, &sc->rxbuf, list) + ath5k_rxbuf_free_skb(sc, bf); - ath5k_debug_dump_bands(sc); + /* Free memory associated with all descriptors */ + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); + sc->desc = NULL; + sc->desc_daddr = 0; - return 0; + kfree(sc->bufptr); + sc->bufptr = NULL; + sc->bbuf = NULL; } -/* - * Set/change channels. We always reset the chip. - * To accomplish this we must first cleanup any pending DMA, - * then restart stuff after a la ath5k_init. - * - * Called with sc->lock. - */ -static int -ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) + +/**************\ +* Queues setup * +\**************/ + +static struct ath5k_txq * +ath5k_txq_setup(struct ath5k_softc *sc, + int qtype, int subtype) { - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, - "channel set, resetting (%u -> %u MHz)\n", - sc->curchan->center_freq, chan->center_freq); + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq *txq; + struct ath5k_txq_info qi = { + .tqi_subtype = subtype, + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT + }; + int qnum; /* - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. + * Enable interrupts only for EOL and DESC conditions. + * We mark tx descriptors to receive a DESC interrupt + * when a tx queue gets deep; otherwise we wait for the + * EOL to reap descriptors. Note that this is done to + * reduce interrupt load and this only defers reaping + * descriptors, never transmitting frames. Aside from + * reducing interrupts this also permits more concurrency. + * The only potential downside is if the tx queue backs + * up in which case the top half of the kernel may backup + * due to a lack of tx descriptors. */ - return ath5k_reset(sc, chan); + qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | + AR5K_TXQ_FLAG_TXDESCINT_ENABLE; + qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); + if (qnum < 0) { + /* + * NB: don't print a message, this happens + * normally on parts with too few tx queues + */ + return ERR_PTR(qnum); + } + if (qnum >= ARRAY_SIZE(sc->txqs)) { + ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n", + qnum, ARRAY_SIZE(sc->txqs)); + ath5k_hw_release_tx_queue(ah, qnum); + return ERR_PTR(-EINVAL); + } + txq = &sc->txqs[qnum]; + if (!txq->setup) { + txq->qnum = qnum; + txq->link = NULL; + INIT_LIST_HEAD(&txq->q); + spin_lock_init(&txq->lock); + txq->setup = true; + } + return &sc->txqs[qnum]; } -static void -ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) +static int +ath5k_beaconq_setup(struct ath5k_hw *ah) { - sc->curmode = mode; + struct ath5k_txq_info qi = { + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT, + /* NB: for dynamic turbo, don't enable any other interrupts */ + .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE + }; - if (mode == AR5K_MODE_11A) { - sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; - } else { - sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; - } + return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); } -static void -ath5k_mode_setup(struct ath5k_softc *sc) +static int +ath5k_beaconq_config(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - u32 rfilt; - - /* configure rx filter */ - rfilt = sc->filter_flags; - ath5k_hw_set_rx_filter(ah, rfilt); + struct ath5k_txq_info qi; + int ret; - if (ath5k_hw_hasbssidmask(ah)) - ath5k_hw_set_bssid_mask(ah, sc->bssidmask); + ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) + goto err; - /* configure operational mode */ - ath5k_hw_set_opmode(ah, sc->opmode); + if (sc->opmode == NL80211_IFTYPE_AP || + sc->opmode == NL80211_IFTYPE_MESH_POINT) { + /* + * Always burst out beacon and CAB traffic + * (aifs = cwmin = cwmax = 0) + */ + qi.tqi_aifs = 0; + qi.tqi_cw_min = 0; + qi.tqi_cw_max = 0; + } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { + /* + * Adhoc mode; backoff between 0 and (2 * cw_min). + */ + qi.tqi_aifs = 0; + qi.tqi_cw_min = 0; + qi.tqi_cw_max = 2 * ah->ah_cw_min; + } - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); -} + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n", + qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max); -static inline int -ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) -{ - int rix; + ret = ath5k_hw_set_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) { + ATH5K_ERR(sc, "%s: unable to update parameters for beacon " + "hardware queue!\n", __func__); + goto err; + } + ret = ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */ + if (ret) + goto err; - /* return base rate on errors */ - if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, - "hw_rix out of bounds: %x\n", hw_rix)) - return 0; + /* reconfigure cabq with ready time to 80% of beacon_interval */ + ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); + if (ret) + goto err; - rix = sc->rate_idx[sc->curband->band][hw_rix]; - if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) - rix = 0; + qi.tqi_ready_time = (sc->bintval * 80) / 100; + ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); + if (ret) + goto err; - return rix; + ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB); +err: + return ret; } -/***************\ -* Buffers setup * -\***************/ - -static -struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) -{ - struct ath_common *common = ath5k_hw_common(sc->ah); - struct sk_buff *skb; +static void +ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) +{ + struct ath5k_buf *bf, *bf0; /* - * Allocate buffer with headroom_needed space for the - * fake physical layer header at the start. + * NB: this assumes output has been stopped and + * we do not need to block ath5k_tx_tasklet */ - skb = ath_rxbuf_alloc(common, - common->rx_bufsize, - GFP_ATOMIC); + spin_lock_bh(&txq->lock); + list_for_each_entry_safe(bf, bf0, &txq->q, list) { + ath5k_debug_printtxbuf(sc, bf); - if (!skb) { - ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - common->rx_bufsize); - return NULL; - } + ath5k_txbuf_free_skb(sc, bf); - *skb_addr = pci_map_single(sc->pdev, - skb->data, common->rx_bufsize, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { - ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); - dev_kfree_skb(skb); - return NULL; + spin_lock_bh(&sc->txbuflock); + list_move_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_bh(&sc->txbuflock); } - return skb; + txq->link = NULL; + spin_unlock_bh(&txq->lock); } -static int -ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +/* + * Drain the transmit queues and reclaim resources. + */ +static void +ath5k_txq_cleanup(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - struct sk_buff *skb = bf->skb; - struct ath5k_desc *ds; - int ret; - - if (!skb) { - skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); - if (!skb) - return -ENOMEM; - bf->skb = skb; - } + unsigned int i; - /* - * Setup descriptors. For receive we always terminate - * the descriptor list with a self-linked entry so we'll - * not get overrun under high load (as can happen with a - * 5212 when ANI processing enables PHY error frames). - * - * To ensure the last descriptor is self-linked we create - * each descriptor as self-linked and add it to the end. As - * each additional descriptor is added the previous self-linked - * entry is "fixed" naturally. This should be safe even - * if DMA is happening. When processing RX interrupts we - * never remove/process the last, self-linked, entry on the - * descriptor list. This ensures the hardware always has - * someplace to write a new frame. - */ - ds = bf->desc; - ds->ds_link = bf->daddr; /* link to self */ - ds->ds_data = bf->skbaddr; - ret = ath5k_hw_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0); - if (ret) { - ATH5K_ERR(sc, "%s: could not setup RX desc\n", __func__); - return ret; + /* XXX return value */ + if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) { + /* don't touch the hardware if marked invalid */ + ath5k_hw_stop_tx_dma(ah, sc->bhalq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n", + ath5k_hw_get_txdp(ah, sc->bhalq)); + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) + if (sc->txqs[i].setup) { + ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, " + "link %p\n", + sc->txqs[i].qnum, + ath5k_hw_get_txdp(ah, + sc->txqs[i].qnum), + sc->txqs[i].link); + } } - if (sc->rxlink != NULL) - *sc->rxlink = bf->daddr; - sc->rxlink = &ds->ds_link; - return 0; + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) + if (sc->txqs[i].setup) + ath5k_txq_drainq(sc, &sc->txqs[i]); } -static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) +static void +ath5k_txq_release(struct ath5k_softc *sc) { - struct ieee80211_hdr *hdr; - enum ath5k_pkt_type htype; - __le16 fc; + struct ath5k_txq *txq = sc->txqs; + unsigned int i; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++) + if (txq->setup) { + ath5k_hw_release_tx_queue(sc->ah, txq->qnum); + txq->setup = false; + } +} - if (ieee80211_is_beacon(fc)) - htype = AR5K_PKT_TYPE_BEACON; - else if (ieee80211_is_probe_resp(fc)) - htype = AR5K_PKT_TYPE_PROBE_RESP; - else if (ieee80211_is_atim(fc)) - htype = AR5K_PKT_TYPE_ATIM; - else if (ieee80211_is_pspoll(fc)) - htype = AR5K_PKT_TYPE_PSPOLL; - else - htype = AR5K_PKT_TYPE_NORMAL; - return htype; -} +/*************\ +* RX Handling * +\*************/ +/* + * Enable the receive h/w following a reset. + */ static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ath5k_txq *txq, int padsize) +ath5k_rx_start(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - struct ath5k_desc *ds = bf->desc; - struct sk_buff *skb = bf->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; - struct ieee80211_rate *rate; - unsigned int mrr_rate[3], mrr_tries[3]; - int i, ret; - u16 hw_rate; - u16 cts_rate = 0; - u16 duration = 0; - u8 rc_flags; - - flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - - /* XXX endianness */ - bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - - rate = ieee80211_get_tx_rate(sc->hw, info); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - flags |= AR5K_TXDESC_NOACK; - - rc_flags = info->control.rates[0].flags; - hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? - rate->hw_value_short : rate->hw_value; - - pktlen = skb->len; + struct ath_common *common = ath5k_hw_common(ah); + struct ath5k_buf *bf; + int ret; - /* FIXME: If we are in g mode and rate is a CCK rate - * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta - * from tx power (value is in dB units already) */ - if (info->control.hw_key) { - keyidx = info->control.hw_key->hw_key_idx; - pktlen += info->control.hw_key->icv_len; - } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - flags |= AR5K_TXDESC_RTSENA; - cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; - duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, - sc->vif, pktlen, info)); - } - if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - flags |= AR5K_TXDESC_CTSENA; - cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; - duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, - sc->vif, pktlen, info)); - } - ret = ah->ah_setup_tx_desc(ah, ds, pktlen, - ieee80211_get_hdrlen_from_skb(skb), padsize, - get_hw_packet_type(skb), - (sc->power_level * 2), - hw_rate, - info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, - cts_rate, duration); - if (ret) - goto err_unmap; + common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz); - memset(mrr_rate, 0, sizeof(mrr_rate)); - memset(mrr_tries, 0, sizeof(mrr_tries)); - for (i = 0; i < 3; i++) { - rate = ieee80211_get_alt_retry_rate(sc->hw, info, i); - if (!rate) - break; + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n", + common->cachelsz, common->rx_bufsize); - mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.rates[i + 1].count; + spin_lock_bh(&sc->rxbuflock); + sc->rxlink = NULL; + list_for_each_entry(bf, &sc->rxbuf, list) { + ret = ath5k_rxbuf_setup(sc, bf); + if (ret != 0) { + spin_unlock_bh(&sc->rxbuflock); + goto err; + } } + bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + ath5k_hw_set_rxdp(ah, bf->daddr); + spin_unlock_bh(&sc->rxbuflock); - ath5k_hw_setup_mrr_tx_desc(ah, ds, - mrr_rate[0], mrr_tries[0], - mrr_rate[1], mrr_tries[1], - mrr_rate[2], mrr_tries[2]); - - ds->ds_link = 0; - ds->ds_data = bf->skbaddr; - - spin_lock_bh(&txq->lock); - list_add_tail(&bf->list, &txq->q); - if (txq->link == NULL) /* is this first packet? */ - ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); - else /* no, so only link it */ - *txq->link = bf->daddr; - - txq->link = &ds->ds_link; - ath5k_hw_start_tx_dma(ah, txq->qnum); - mmiowb(); - spin_unlock_bh(&txq->lock); + ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ + ath5k_mode_setup(sc); /* set filters, etc. */ + ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ return 0; -err_unmap: - pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); +err: return ret; } -/*******************\ -* Descriptors setup * -\*******************/ - -static int -ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) +/* + * Disable the receive h/w in preparation for a reset. + */ +static void +ath5k_rx_stop(struct ath5k_softc *sc) { - struct ath5k_desc *ds; - struct ath5k_buf *bf; - dma_addr_t da; - unsigned int i; - int ret; + struct ath5k_hw *ah = sc->ah; - /* allocate descriptors */ - sc->desc_len = sizeof(struct ath5k_desc) * - (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); - sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); - if (sc->desc == NULL) { - ATH5K_ERR(sc, "can't allocate descriptors\n"); - ret = -ENOMEM; - goto err; - } - ds = sc->desc; - da = sc->desc_daddr; - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", - ds, sc->desc_len, (unsigned long long)sc->desc_daddr); + ath5k_hw_stop_rx_pcu(ah); /* disable PCU */ + ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ + ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ - bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, - sizeof(struct ath5k_buf), GFP_KERNEL); - if (bf == NULL) { - ATH5K_ERR(sc, "can't allocate bufptr\n"); - ret = -ENOMEM; - goto err_free; - } - sc->bufptr = bf; + ath5k_debug_printrxbuffs(sc, ah); +} - INIT_LIST_HEAD(&sc->rxbuf); - for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { - bf->desc = ds; - bf->daddr = da; - list_add_tail(&bf->list, &sc->rxbuf); - } +static unsigned int +ath5k_rx_decrypted(struct ath5k_softc *sc, struct sk_buff *skb, + struct ath5k_rx_status *rs) +{ + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + struct ieee80211_hdr *hdr = (void *)skb->data; + unsigned int keyix, hlen; - INIT_LIST_HEAD(&sc->txbuf); - sc->txbuf_len = ATH_TXBUF; - for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, - da += sizeof(*ds)) { - bf->desc = ds; - bf->daddr = da; - list_add_tail(&bf->list, &sc->txbuf); - } + if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && + rs->rs_keyix != AR5K_RXKEYIX_INVALID) + return RX_FLAG_DECRYPTED; - /* beacon buffer */ - bf->desc = ds; - bf->daddr = da; - sc->bbuf = bf; + /* Apparently when a default key is used to decrypt the packet + the hw does not set the index used to decrypt. In such cases + get the index from the packet. */ + hlen = ieee80211_hdrlen(hdr->frame_control); + if (ieee80211_has_protected(hdr->frame_control) && + !(rs->rs_status & AR5K_RXERR_DECRYPT) && + skb->len >= hlen + 4) { + keyix = skb->data[hlen + 3] >> 6; + + if (test_bit(keyix, common->keymap)) + return RX_FLAG_DECRYPTED; + } return 0; -err_free: - pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); -err: - sc->desc = NULL; - return ret; } + static void -ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) +ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, + struct ieee80211_rx_status *rxs) { - struct ath5k_buf *bf; + struct ath_common *common = ath5k_hw_common(sc->ah); + u64 tsf, bc_tstamp; + u32 hw_tu; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - ath5k_txbuf_free_skb(sc, sc->bbuf); - list_for_each_entry(bf, &sc->txbuf, list) - ath5k_txbuf_free_skb(sc, bf); - list_for_each_entry(bf, &sc->rxbuf, list) - ath5k_rxbuf_free_skb(sc, bf); + if (ieee80211_is_beacon(mgmt->frame_control) && + le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && + memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { + /* + * Received an IBSS beacon with the same BSSID. Hardware *must* + * have updated the local TSF. We have to work around various + * hardware bugs, though... + */ + tsf = ath5k_hw_get_tsf64(sc->ah); + bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); + hw_tu = TSF_TO_TU(tsf); - /* Free memory associated with all descriptors */ - pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); - sc->desc = NULL; - sc->desc_daddr = 0; + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", + (unsigned long long)bc_tstamp, + (unsigned long long)rxs->mactime, + (unsigned long long)(rxs->mactime - bc_tstamp), + (unsigned long long)tsf); - kfree(sc->bufptr); - sc->bufptr = NULL; - sc->bbuf = NULL; -} + /* + * Sometimes the HW will give us a wrong tstamp in the rx + * status, causing the timestamp extension to go wrong. + * (This seems to happen especially with beacon frames bigger + * than 78 byte (incl. FCS)) + * But we know that the receive timestamp must be later than the + * timestamp of the beacon since HW must have synced to that. + * + * NOTE: here we assume mactime to be after the frame was + * received, not like mac80211 which defines it at the start. + */ + if (bc_tstamp > rxs->mactime) { + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "fixing mactime from %llx to %llx\n", + (unsigned long long)rxs->mactime, + (unsigned long long)tsf); + rxs->mactime = tsf; + } + /* + * Local TSF might have moved higher than our beacon timers, + * in that case we have to update them to continue sending + * beacons. This also takes care of synchronizing beacon sending + * times with other stations. + */ + if (hw_tu >= sc->nexttbtt) + ath5k_beacon_update_timers(sc, bc_tstamp); + } +} +static void +ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + /* only beacons from our BSSID */ + if (!ieee80211_is_beacon(mgmt->frame_control) || + memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) + return; + ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, + rssi); -/**************\ -* Queues setup * -\**************/ + /* in IBSS mode we should keep RSSI statistics per neighbour */ + /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ +} -static struct ath5k_txq * -ath5k_txq_setup(struct ath5k_softc *sc, - int qtype, int subtype) +/* + * Compute padding position. skb must contain an IEEE 802.11 frame + */ +static int ath5k_common_padpos(struct sk_buff *skb) { - struct ath5k_hw *ah = sc->ah; - struct ath5k_txq *txq; - struct ath5k_txq_info qi = { - .tqi_subtype = subtype, - .tqi_aifs = AR5K_TXQ_USEDEFAULT, - .tqi_cw_min = AR5K_TXQ_USEDEFAULT, - .tqi_cw_max = AR5K_TXQ_USEDEFAULT - }; - int qnum; + struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; + __le16 frame_control = hdr->frame_control; + int padpos = 24; - /* - * Enable interrupts only for EOL and DESC conditions. - * We mark tx descriptors to receive a DESC interrupt - * when a tx queue gets deep; otherwise we wait for the - * EOL to reap descriptors. Note that this is done to - * reduce interrupt load and this only defers reaping - * descriptors, never transmitting frames. Aside from - * reducing interrupts this also permits more concurrency. - * The only potential downside is if the tx queue backs - * up in which case the top half of the kernel may backup - * due to a lack of tx descriptors. - */ - qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | - AR5K_TXQ_FLAG_TXDESCINT_ENABLE; - qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); - if (qnum < 0) { - /* - * NB: don't print a message, this happens - * normally on parts with too few tx queues - */ - return ERR_PTR(qnum); - } - if (qnum >= ARRAY_SIZE(sc->txqs)) { - ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n", - qnum, ARRAY_SIZE(sc->txqs)); - ath5k_hw_release_tx_queue(ah, qnum); - return ERR_PTR(-EINVAL); + if (ieee80211_has_a4(frame_control)) { + padpos += ETH_ALEN; } - txq = &sc->txqs[qnum]; - if (!txq->setup) { - txq->qnum = qnum; - txq->link = NULL; - INIT_LIST_HEAD(&txq->q); - spin_lock_init(&txq->lock); - txq->setup = true; + if (ieee80211_is_data_qos(frame_control)) { + padpos += IEEE80211_QOS_CTL_LEN; } - return &sc->txqs[qnum]; + + return padpos; } -static int -ath5k_beaconq_setup(struct ath5k_hw *ah) +/* + * This function expects an 802.11 frame and returns the number of + * bytes added, or -1 if we don't have enough header room. + */ +static int ath5k_add_padding(struct sk_buff *skb) { - struct ath5k_txq_info qi = { - .tqi_aifs = AR5K_TXQ_USEDEFAULT, - .tqi_cw_min = AR5K_TXQ_USEDEFAULT, - .tqi_cw_max = AR5K_TXQ_USEDEFAULT, - /* NB: for dynamic turbo, don't enable any other interrupts */ - .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE - }; + int padpos = ath5k_common_padpos(skb); + int padsize = padpos & 3; - return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); -} + if (padsize && skb->len>padpos) { -static int -ath5k_beaconq_config(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - struct ath5k_txq_info qi; - int ret; + if (skb_headroom(skb) < padsize) + return -1; - ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); - if (ret) - goto err; + skb_push(skb, padsize); + memmove(skb->data, skb->data+padsize, padpos); + return padsize; + } - if (sc->opmode == NL80211_IFTYPE_AP || - sc->opmode == NL80211_IFTYPE_MESH_POINT) { - /* - * Always burst out beacon and CAB traffic - * (aifs = cwmin = cwmax = 0) - */ - qi.tqi_aifs = 0; - qi.tqi_cw_min = 0; - qi.tqi_cw_max = 0; - } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { - /* - * Adhoc mode; backoff between 0 and (2 * cw_min). - */ - qi.tqi_aifs = 0; - qi.tqi_cw_min = 0; - qi.tqi_cw_max = 2 * ah->ah_cw_min; - } + return 0; +} - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n", - qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max); +/* + * The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = 4 - (hdrlen & 3); however, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. We must not try to + * remove padding from short control frames that do not have a + * payload. + * + * This function expects an 802.11 frame and returns the number of + * bytes removed. + */ +static int ath5k_remove_padding(struct sk_buff *skb) +{ + int padpos = ath5k_common_padpos(skb); + int padsize = padpos & 3; - ret = ath5k_hw_set_tx_queueprops(ah, sc->bhalq, &qi); - if (ret) { - ATH5K_ERR(sc, "%s: unable to update parameters for beacon " - "hardware queue!\n", __func__); - goto err; + if (padsize && skb->len>=padpos+padsize) { + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + return padsize; } - ret = ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */ - if (ret) - goto err; - - /* reconfigure cabq with ready time to 80% of beacon_interval */ - ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); - if (ret) - goto err; - - qi.tqi_ready_time = (sc->bintval * 80) / 100; - ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); - if (ret) - goto err; - ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB); -err: - return ret; + return 0; } static void -ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) +ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, + struct ath5k_rx_status *rs) { - struct ath5k_buf *bf, *bf0; + struct ieee80211_rx_status *rxs; + + ath5k_remove_padding(skb); + + rxs = IEEE80211_SKB_RXCB(skb); + + rxs->flag = 0; + if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) + rxs->flag |= RX_FLAG_MMIC_ERROR; /* - * NB: this assumes output has been stopped and - * we do not need to block ath5k_tx_tasklet + * always extend the mac timestamp, since this information is + * also needed for proper IBSS merging. + * + * XXX: it might be too late to do it here, since rs_tstamp is + * 15bit only. that means TSF extension has to be done within + * 32768usec (about 32ms). it might be necessary to move this to + * the interrupt handler, like it is done in madwifi. + * + * Unfortunately we don't know when the hardware takes the rx + * timestamp (beginning of phy frame, data frame, end of rx?). + * The only thing we know is that it is hardware specific... + * On AR5213 it seems the rx timestamp is at the end of the + * frame, but i'm not sure. + * + * NOTE: mac80211 defines mactime at the beginning of the first + * data symbol. Since we don't have any time references it's + * impossible to comply to that. This affects IBSS merge only + * right now, so it's not too bad... */ - spin_lock_bh(&txq->lock); - list_for_each_entry_safe(bf, bf0, &txq->q, list) { - ath5k_debug_printtxbuf(sc, bf); - - ath5k_txbuf_free_skb(sc, bf); + rxs->mactime = ath5k_extend_tsf(sc->ah, rs->rs_tstamp); + rxs->flag |= RX_FLAG_TSFT; - spin_lock_bh(&sc->txbuflock); - list_move_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock_bh(&sc->txbuflock); - } - txq->link = NULL; - spin_unlock_bh(&txq->lock); -} + rxs->freq = sc->curchan->center_freq; + rxs->band = sc->curband->band; -/* - * Drain the transmit queues and reclaim resources. - */ -static void -ath5k_txq_cleanup(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - unsigned int i; + rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi; - /* XXX return value */ - if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) { - /* don't touch the hardware if marked invalid */ - ath5k_hw_stop_tx_dma(ah, sc->bhalq); - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n", - ath5k_hw_get_txdp(ah, sc->bhalq)); - for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) - if (sc->txqs[i].setup) { - ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, " - "link %p\n", - sc->txqs[i].qnum, - ath5k_hw_get_txdp(ah, - sc->txqs[i].qnum), - sc->txqs[i].link); - } - } + rxs->antenna = rs->rs_antenna; - for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) - if (sc->txqs[i].setup) - ath5k_txq_drainq(sc, &sc->txqs[i]); -} + if (rs->rs_antenna > 0 && rs->rs_antenna < 5) + sc->stats.antenna_rx[rs->rs_antenna]++; + else + sc->stats.antenna_rx[0]++; /* invalid */ -static void -ath5k_txq_release(struct ath5k_softc *sc) -{ - struct ath5k_txq *txq = sc->txqs; - unsigned int i; + rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs->rs_rate); + rxs->flag |= ath5k_rx_decrypted(sc, skb, rs); - for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++) - if (txq->setup) { - ath5k_hw_release_tx_queue(sc->ah, txq->qnum); - txq->setup = false; - } -} + if (rxs->rate_idx >= 0 && rs->rs_rate == + sc->curband->bitrates[rxs->rate_idx].hw_value_short) + rxs->flag |= RX_FLAG_SHORTPRE; + ath5k_debug_dump_skb(sc, skb, "RX ", 0); + ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi); + /* check beacons in IBSS mode */ + if (sc->opmode == NL80211_IFTYPE_ADHOC) + ath5k_check_ibss_tsf(sc, skb, rxs); -/*************\ -* RX Handling * -\*************/ + ieee80211_rx(sc->hw, skb); +} -/* - * Enable the receive h/w following a reset. +/** ath5k_frame_receive_ok() - Do we want to receive this frame or not? + * + * Check if we want to further process this frame or not. Also update + * statistics. Return true if we want this frame, false if not. */ -static int -ath5k_rx_start(struct ath5k_softc *sc) +static bool +ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) { - struct ath5k_hw *ah = sc->ah; - struct ath_common *common = ath5k_hw_common(ah); - struct ath5k_buf *bf; - int ret; - - common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n", - common->cachelsz, common->rx_bufsize); + sc->stats.rx_all_count++; - spin_lock_bh(&sc->rxbuflock); - sc->rxlink = NULL; - list_for_each_entry(bf, &sc->rxbuf, list) { - ret = ath5k_rxbuf_setup(sc, bf); - if (ret != 0) { - spin_unlock_bh(&sc->rxbuflock); - goto err; + if (unlikely(rs->rs_status)) { + if (rs->rs_status & AR5K_RXERR_CRC) + sc->stats.rxerr_crc++; + if (rs->rs_status & AR5K_RXERR_FIFO) + sc->stats.rxerr_fifo++; + if (rs->rs_status & AR5K_RXERR_PHY) { + sc->stats.rxerr_phy++; + if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) + sc->stats.rxerr_phy_code[rs->rs_phyerr]++; + return false; + } + if (rs->rs_status & AR5K_RXERR_DECRYPT) { + /* + * Decrypt error. If the error occurred + * because there was no hardware key, then + * let the frame through so the upper layers + * can process it. This is necessary for 5210 + * parts which have no way to setup a ``clear'' + * key cache entry. + * + * XXX do key cache faulting + */ + sc->stats.rxerr_decrypt++; + if (rs->rs_keyix == AR5K_RXKEYIX_INVALID && + !(rs->rs_status & AR5K_RXERR_CRC)) + return true; + } + if (rs->rs_status & AR5K_RXERR_MIC) { + sc->stats.rxerr_mic++; + return true; } - } - bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); - ath5k_hw_set_rxdp(ah, bf->daddr); - spin_unlock_bh(&sc->rxbuflock); - ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ - ath5k_mode_setup(sc); /* set filters, etc. */ - ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ + /* reject any frames with non-crypto errors */ + if (rs->rs_status & ~(AR5K_RXERR_DECRYPT)) + return false; + } - return 0; -err: - return ret; + if (unlikely(rs->rs_more)) { + sc->stats.rxerr_jumbo++; + return false; + } + return true; } -/* - * Disable the receive h/w in preparation for a reset. - */ static void -ath5k_rx_stop(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - - ath5k_hw_stop_rx_pcu(ah); /* disable PCU */ - ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ - ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ - - ath5k_debug_printrxbuffs(sc, ah); -} - -static unsigned int -ath5k_rx_decrypted(struct ath5k_softc *sc, struct sk_buff *skb, - struct ath5k_rx_status *rs) +ath5k_tasklet_rx(unsigned long data) { + struct ath5k_rx_status rs = {}; + struct sk_buff *skb, *next_skb; + dma_addr_t next_skb_addr; + struct ath5k_softc *sc = (void *)data; struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); - struct ieee80211_hdr *hdr = (void *)skb->data; - unsigned int keyix, hlen; + struct ath5k_buf *bf; + struct ath5k_desc *ds; + int ret; - if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && - rs->rs_keyix != AR5K_RXKEYIX_INVALID) - return RX_FLAG_DECRYPTED; + spin_lock(&sc->rxbuflock); + if (list_empty(&sc->rxbuf)) { + ATH5K_WARN(sc, "empty rx buf pool\n"); + goto unlock; + } + do { + bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + BUG_ON(bf->skb == NULL); + skb = bf->skb; + ds = bf->desc; - /* Apparently when a default key is used to decrypt the packet - the hw does not set the index used to decrypt. In such cases - get the index from the packet. */ - hlen = ieee80211_hdrlen(hdr->frame_control); - if (ieee80211_has_protected(hdr->frame_control) && - !(rs->rs_status & AR5K_RXERR_DECRYPT) && - skb->len >= hlen + 4) { - keyix = skb->data[hlen + 3] >> 6; + /* bail if HW is still using self-linked descriptor */ + if (ath5k_hw_get_rxdp(sc->ah) == bf->daddr) + break; - if (test_bit(keyix, common->keymap)) - return RX_FLAG_DECRYPTED; - } + ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, "error in processing rx descriptor\n"); + sc->stats.rxerr_proc++; + break; + } - return 0; -} + if (ath5k_receive_frame_ok(sc, &rs)) { + next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); + /* + * If we can't replace bf->skb with a new skb under + * memory pressure, just skip this packet + */ + if (!next_skb) + goto next; -static void -ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, - struct ieee80211_rx_status *rxs) -{ - struct ath_common *common = ath5k_hw_common(sc->ah); - u64 tsf, bc_tstamp; - u32 hw_tu; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + pci_unmap_single(sc->pdev, bf->skbaddr, + common->rx_bufsize, + PCI_DMA_FROMDEVICE); - if (ieee80211_is_beacon(mgmt->frame_control) && - le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { - /* - * Received an IBSS beacon with the same BSSID. Hardware *must* - * have updated the local TSF. We have to work around various - * hardware bugs, though... - */ - tsf = ath5k_hw_get_tsf64(sc->ah); - bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); - hw_tu = TSF_TO_TU(tsf); + skb_put(skb, rs.rs_datalen); - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", - (unsigned long long)bc_tstamp, - (unsigned long long)rxs->mactime, - (unsigned long long)(rxs->mactime - bc_tstamp), - (unsigned long long)tsf); + ath5k_receive_frame(sc, skb, &rs); - /* - * Sometimes the HW will give us a wrong tstamp in the rx - * status, causing the timestamp extension to go wrong. - * (This seems to happen especially with beacon frames bigger - * than 78 byte (incl. FCS)) - * But we know that the receive timestamp must be later than the - * timestamp of the beacon since HW must have synced to that. - * - * NOTE: here we assume mactime to be after the frame was - * received, not like mac80211 which defines it at the start. - */ - if (bc_tstamp > rxs->mactime) { - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "fixing mactime from %llx to %llx\n", - (unsigned long long)rxs->mactime, - (unsigned long long)tsf); - rxs->mactime = tsf; + bf->skb = next_skb; + bf->skbaddr = next_skb_addr; } - - /* - * Local TSF might have moved higher than our beacon timers, - * in that case we have to update them to continue sending - * beacons. This also takes care of synchronizing beacon sending - * times with other stations. - */ - if (hw_tu >= sc->nexttbtt) - ath5k_beacon_update_timers(sc, bc_tstamp); - } +next: + list_move_tail(&bf->list, &sc->rxbuf); + } while (ath5k_rxbuf_setup(sc, bf) == 0); +unlock: + spin_unlock(&sc->rxbuflock); } -static void -ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) -{ - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - struct ath5k_hw *ah = sc->ah; - struct ath_common *common = ath5k_hw_common(ah); - /* only beacons from our BSSID */ - if (!ieee80211_is_beacon(mgmt->frame_control) || - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) - return; +/*************\ +* TX Handling * +\*************/ - ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, - rssi); +static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_buf *bf; + unsigned long flags; + int padsize; - /* in IBSS mode we should keep RSSI statistics per neighbour */ - /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ -} + ath5k_debug_dump_skb(sc, skb, "TX ", 1); -/* - * Compute padding position. skb must contain an IEEE 802.11 frame - */ -static int ath5k_common_padpos(struct sk_buff *skb) -{ - struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; - __le16 frame_control = hdr->frame_control; - int padpos = 24; + /* + * The hardware expects the header padded to 4 byte boundaries. + * If this is not the case, we add the padding after the header. + */ + padsize = ath5k_add_padding(skb); + if (padsize < 0) { + ATH5K_ERR(sc, "tx hdrlen not %%4: not enough" + " headroom to pad"); + goto drop_packet; + } - if (ieee80211_has_a4(frame_control)) { - padpos += ETH_ALEN; + spin_lock_irqsave(&sc->txbuflock, flags); + if (list_empty(&sc->txbuf)) { + ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); + spin_unlock_irqrestore(&sc->txbuflock, flags); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); + goto drop_packet; } - if (ieee80211_is_data_qos(frame_control)) { - padpos += IEEE80211_QOS_CTL_LEN; + bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); + list_del(&bf->list); + sc->txbuf_len--; + if (list_empty(&sc->txbuf)) + ieee80211_stop_queues(hw); + spin_unlock_irqrestore(&sc->txbuflock, flags); + + bf->skb = skb; + + if (ath5k_txbuf_setup(sc, bf, txq, padsize)) { + bf->skb = NULL; + spin_lock_irqsave(&sc->txbuflock, flags); + list_add_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_irqrestore(&sc->txbuflock, flags); + goto drop_packet; } + return NETDEV_TX_OK; - return padpos; +drop_packet: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } -/* - * This function expects an 802.11 frame and returns the number of - * bytes added, or -1 if we don't have enough header room. - */ -static int ath5k_add_padding(struct sk_buff *skb) + +static void +ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) { - int padpos = ath5k_common_padpos(skb); - int padsize = padpos & 3; + struct ath5k_tx_status ts = {}; + struct ath5k_buf *bf, *bf0; + struct ath5k_desc *ds; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + int i, ret; - if (padsize && skb->len>padpos) { + spin_lock(&txq->lock); + list_for_each_entry_safe(bf, bf0, &txq->q, list) { + ds = bf->desc; - if (skb_headroom(skb) < padsize) - return -1; + /* + * It's possible that the hardware can say the buffer is + * completed when it hasn't yet loaded the ds_link from + * host memory and moved on. If there are more TX + * descriptors in the queue, wait for TXDP to change + * before processing this one. + */ + if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && + !list_is_last(&bf->list, &txq->q)) + break; - skb_push(skb, padsize); - memmove(skb->data, skb->data+padsize, padpos); - return padsize; - } + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, "error %d while processing queue %u\n", + ret, txq->qnum); + break; + } - return 0; -} - -/* - * The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = 4 - (hdrlen & 3); however, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. We must not try to - * remove padding from short control frames that do not have a - * payload. - * - * This function expects an 802.11 frame and returns the number of - * bytes removed. - */ -static int ath5k_remove_padding(struct sk_buff *skb) -{ - int padpos = ath5k_common_padpos(skb); - int padsize = padpos & 3; - - if (padsize && skb->len>=padpos+padsize) { - memmove(skb->data + padsize, skb->data, padpos); - skb_pull(skb, padsize); - return padsize; - } - - return 0; -} - -static void -ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, - struct ath5k_rx_status *rs) -{ - struct ieee80211_rx_status *rxs; - - ath5k_remove_padding(skb); - - rxs = IEEE80211_SKB_RXCB(skb); - - rxs->flag = 0; - if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) - rxs->flag |= RX_FLAG_MMIC_ERROR; - - /* - * always extend the mac timestamp, since this information is - * also needed for proper IBSS merging. - * - * XXX: it might be too late to do it here, since rs_tstamp is - * 15bit only. that means TSF extension has to be done within - * 32768usec (about 32ms). it might be necessary to move this to - * the interrupt handler, like it is done in madwifi. - * - * Unfortunately we don't know when the hardware takes the rx - * timestamp (beginning of phy frame, data frame, end of rx?). - * The only thing we know is that it is hardware specific... - * On AR5213 it seems the rx timestamp is at the end of the - * frame, but i'm not sure. - * - * NOTE: mac80211 defines mactime at the beginning of the first - * data symbol. Since we don't have any time references it's - * impossible to comply to that. This affects IBSS merge only - * right now, so it's not too bad... - */ - rxs->mactime = ath5k_extend_tsf(sc->ah, rs->rs_tstamp); - rxs->flag |= RX_FLAG_TSFT; - - rxs->freq = sc->curchan->center_freq; - rxs->band = sc->curband->band; - - rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi; - - rxs->antenna = rs->rs_antenna; - - if (rs->rs_antenna > 0 && rs->rs_antenna < 5) - sc->stats.antenna_rx[rs->rs_antenna]++; - else - sc->stats.antenna_rx[0]++; /* invalid */ - - rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs->rs_rate); - rxs->flag |= ath5k_rx_decrypted(sc, skb, rs); - - if (rxs->rate_idx >= 0 && rs->rs_rate == - sc->curband->bitrates[rxs->rate_idx].hw_value_short) - rxs->flag |= RX_FLAG_SHORTPRE; - - ath5k_debug_dump_skb(sc, skb, "RX ", 0); - - ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi); - - /* check beacons in IBSS mode */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) - ath5k_check_ibss_tsf(sc, skb, rxs); - - ieee80211_rx(sc->hw, skb); -} - -/** ath5k_frame_receive_ok() - Do we want to receive this frame or not? - * - * Check if we want to further process this frame or not. Also update - * statistics. Return true if we want this frame, false if not. - */ -static bool -ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) -{ - sc->stats.rx_all_count++; - - if (unlikely(rs->rs_status)) { - if (rs->rs_status & AR5K_RXERR_CRC) - sc->stats.rxerr_crc++; - if (rs->rs_status & AR5K_RXERR_FIFO) - sc->stats.rxerr_fifo++; - if (rs->rs_status & AR5K_RXERR_PHY) { - sc->stats.rxerr_phy++; - if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) - sc->stats.rxerr_phy_code[rs->rs_phyerr]++; - return false; - } - if (rs->rs_status & AR5K_RXERR_DECRYPT) { - /* - * Decrypt error. If the error occurred - * because there was no hardware key, then - * let the frame through so the upper layers - * can process it. This is necessary for 5210 - * parts which have no way to setup a ``clear'' - * key cache entry. - * - * XXX do key cache faulting - */ - sc->stats.rxerr_decrypt++; - if (rs->rs_keyix == AR5K_RXKEYIX_INVALID && - !(rs->rs_status & AR5K_RXERR_CRC)) - return true; - } - if (rs->rs_status & AR5K_RXERR_MIC) { - sc->stats.rxerr_mic++; - return true; - } - - /* reject any frames with non-crypto errors */ - if (rs->rs_status & ~(AR5K_RXERR_DECRYPT)) - return false; - } - - if (unlikely(rs->rs_more)) { - sc->stats.rxerr_jumbo++; - return false; - } - return true; -} - -static void -ath5k_tasklet_rx(unsigned long data) -{ - struct ath5k_rx_status rs = {}; - struct sk_buff *skb, *next_skb; - dma_addr_t next_skb_addr; - struct ath5k_softc *sc = (void *)data; - struct ath5k_hw *ah = sc->ah; - struct ath_common *common = ath5k_hw_common(ah); - struct ath5k_buf *bf; - struct ath5k_desc *ds; - int ret; - - spin_lock(&sc->rxbuflock); - if (list_empty(&sc->rxbuf)) { - ATH5K_WARN(sc, "empty rx buf pool\n"); - goto unlock; - } - do { - bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); - BUG_ON(bf->skb == NULL); - skb = bf->skb; - ds = bf->desc; - - /* bail if HW is still using self-linked descriptor */ - if (ath5k_hw_get_rxdp(sc->ah) == bf->daddr) - break; - - ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); - if (unlikely(ret == -EINPROGRESS)) - break; - else if (unlikely(ret)) { - ATH5K_ERR(sc, "error in processing rx descriptor\n"); - sc->stats.rxerr_proc++; - break; - } - - if (ath5k_receive_frame_ok(sc, &rs)) { - next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); - - /* - * If we can't replace bf->skb with a new skb under - * memory pressure, just skip this packet - */ - if (!next_skb) - goto next; - - pci_unmap_single(sc->pdev, bf->skbaddr, - common->rx_bufsize, - PCI_DMA_FROMDEVICE); - - skb_put(skb, rs.rs_datalen); - - ath5k_receive_frame(sc, skb, &rs); - - bf->skb = next_skb; - bf->skbaddr = next_skb_addr; - } -next: - list_move_tail(&bf->list, &sc->rxbuf); - } while (ath5k_rxbuf_setup(sc, bf) == 0); -unlock: - spin_unlock(&sc->rxbuflock); -} - - -/*************\ -* TX Handling * -\*************/ - -static void -ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) -{ - struct ath5k_tx_status ts = {}; - struct ath5k_buf *bf, *bf0; - struct ath5k_desc *ds; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - int i, ret; - - spin_lock(&txq->lock); - list_for_each_entry_safe(bf, bf0, &txq->q, list) { - ds = bf->desc; - - /* - * It's possible that the hardware can say the buffer is - * completed when it hasn't yet loaded the ds_link from - * host memory and moved on. If there are more TX - * descriptors in the queue, wait for TXDP to change - * before processing this one. - */ - if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && - !list_is_last(&bf->list, &txq->q)) - break; - - ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); - if (unlikely(ret == -EINPROGRESS)) - break; - else if (unlikely(ret)) { - ATH5K_ERR(sc, "error %d while processing queue %u\n", - ret, txq->qnum); - break; - } - - sc->stats.tx_all_count++; - skb = bf->skb; - info = IEEE80211_SKB_CB(skb); - bf->skb = NULL; + sc->stats.tx_all_count++; + skb = bf->skb; + info = IEEE80211_SKB_CB(skb); + bf->skb = NULL; pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); @@ -2308,6 +1702,43 @@ err_unmap: return ret; } +/* + * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, + * this is called only once at config_bss time, for AP we do it every + * SWBA interrupt so that the TIM will reflect buffered frames. + * + * Called with the beacon lock. + */ +static int +ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int ret; + struct ath5k_softc *sc = hw->priv; + struct sk_buff *skb; + + if (WARN_ON(!vif)) { + ret = -EINVAL; + goto out; + } + + skb = ieee80211_beacon_get(hw, vif); + + if (!skb) { + ret = -ENOMEM; + goto out; + } + + ath5k_debug_dump_skb(sc, skb, "BC ", 1); + + ath5k_txbuf_free_skb(sc, sc->bbuf); + sc->bbuf->skb = skb; + ret = ath5k_beacon_setup(sc, sc->bbuf); + if (ret) + sc->bbuf->skb = NULL; +out: + return ret; +} + /* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is @@ -2385,7 +1816,6 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->bsent++; } - /** * ath5k_beacon_update_timers - update beacon timers * @@ -2487,7 +1917,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : ""); } - /** * ath5k_beacon_config - Configure the beacon queues and interrupts * @@ -2566,156 +1995,6 @@ static void ath5k_tasklet_beacon(unsigned long data) * Interrupt handling * \********************/ -static int -ath5k_init(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - struct ath_common *common = ath5k_hw_common(ah); - int ret, i; - - mutex_lock(&sc->lock); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); - - /* - * Stop anything previously setup. This is safe - * no matter this is the first time through or not. - */ - ath5k_stop_locked(sc); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - sc->curchan = sc->hw->conf.channel; - sc->curband = &sc->sbands[sc->curchan->band]; - sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | - AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; - - ret = ath5k_reset(sc, NULL); - if (ret) - goto done; - - ath5k_rfkill_hw_start(ah); - - /* - * Reset the key cache since some parts do not reset the - * contents on initial power up or resume from suspend. - */ - for (i = 0; i < common->keymax; i++) - ath_hw_keyreset(common, (u16)i); - - ath5k_hw_set_ack_bitrate_high(ah, true); - ret = 0; -done: - mmiowb(); - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_stop_locked(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", - test_bit(ATH_STAT_INVALID, sc->status)); - - /* - * Shutdown the hardware and driver: - * stop output from above - * disable interrupts - * turn off timers - * turn off the radio - * clear transmit machinery - * clear receive machinery - * drain and release tx queues - * reclaim beacon resources - * power down hardware - * - * Note that some of this work is not possible if the - * hardware is gone (invalid). - */ - ieee80211_stop_queues(sc->hw); - - if (!test_bit(ATH_STAT_INVALID, sc->status)) { - ath5k_led_off(sc); - ath5k_hw_set_imr(ah, 0); - synchronize_irq(sc->pdev->irq); - } - ath5k_txq_cleanup(sc); - if (!test_bit(ATH_STAT_INVALID, sc->status)) { - ath5k_rx_stop(sc); - ath5k_hw_phy_disable(ah); - } - - return 0; -} - -static void stop_tasklets(struct ath5k_softc *sc) -{ - tasklet_kill(&sc->rxtq); - tasklet_kill(&sc->txtq); - tasklet_kill(&sc->calib); - tasklet_kill(&sc->beacontq); - tasklet_kill(&sc->ani_tasklet); -} - -/* - * Stop the device, grabbing the top-level lock to protect - * against concurrent entry through ath5k_init (which can happen - * if another thread does a system call and the thread doing the - * stop is preempted). - */ -static int -ath5k_stop_hw(struct ath5k_softc *sc) -{ - int ret; - - mutex_lock(&sc->lock); - ret = ath5k_stop_locked(sc); - if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { - /* - * Don't set the card in full sleep mode! - * - * a) When the device is in this state it must be carefully - * woken up or references to registers in the PCI clock - * domain may freeze the bus (and system). This varies - * by chip and is mostly an issue with newer parts - * (madwifi sources mentioned srev >= 0x78) that go to - * sleep more quickly. - * - * b) On older chips full sleep results a weird behaviour - * during wakeup. I tested various cards with srev < 0x78 - * and they don't wake up after module reload, a second - * module reload is needed to bring the card up again. - * - * Until we figure out what's going on don't enable - * full chip reset on any chip (this is what Legacy HAL - * and Sam's HAL do anyway). Instead Perform a full reset - * on the device (same as initial state after attach) and - * leave it idle (keep MAC/BB on warm reset) */ - ret = ath5k_hw_on_hold(sc->ah); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, - "putting device to sleep\n"); - } - ath5k_txbuf_free_skb(sc, sc->bbuf); - - mmiowb(); - mutex_unlock(&sc->lock); - - stop_tasklets(sc); - - ath5k_rfkill_hw_stop(sc->ah); - - return ret; -} - static void ath5k_intr_calibration_poll(struct ath5k_hw *ah) { @@ -2878,68 +2157,158 @@ ath5k_tasklet_ani(unsigned long data) } -/********************\ -* Mac80211 functions * -\********************/ +/*************************\ +* Initialization routines * +\*************************/ static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +ath5k_stop_locked(struct ath5k_softc *sc) { - struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; - return ath5k_tx_queue(hw, skb, sc->txq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", + test_bit(ATH_STAT_INVALID, sc->status)); + + /* + * Shutdown the hardware and driver: + * stop output from above + * disable interrupts + * turn off timers + * turn off the radio + * clear transmit machinery + * clear receive machinery + * drain and release tx queues + * reclaim beacon resources + * power down hardware + * + * Note that some of this work is not possible if the + * hardware is gone (invalid). + */ + ieee80211_stop_queues(sc->hw); + + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_led_off(sc); + ath5k_hw_set_imr(ah, 0); + synchronize_irq(sc->pdev->irq); + } + ath5k_txq_cleanup(sc); + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_rx_stop(sc); + ath5k_hw_phy_disable(ah); + } + + return 0; } -static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath5k_txq *txq) +static int +ath5k_init(struct ath5k_softc *sc) { - struct ath5k_softc *sc = hw->priv; - struct ath5k_buf *bf; - unsigned long flags; - int padsize; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + int ret, i; - ath5k_debug_dump_skb(sc, skb, "TX ", 1); + mutex_lock(&sc->lock); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); /* - * The hardware expects the header padded to 4 byte boundaries. - * If this is not the case, we add the padding after the header. + * Stop anything previously setup. This is safe + * no matter this is the first time through or not. */ - padsize = ath5k_add_padding(skb); - if (padsize < 0) { - ATH5K_ERR(sc, "tx hdrlen not %%4: not enough" - " headroom to pad"); - goto drop_packet; - } + ath5k_stop_locked(sc); - spin_lock_irqsave(&sc->txbuflock, flags); - if (list_empty(&sc->txbuf)) { - ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); - spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); - goto drop_packet; - } - bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); - list_del(&bf->list); - sc->txbuf_len--; - if (list_empty(&sc->txbuf)) - ieee80211_stop_queues(hw); - spin_unlock_irqrestore(&sc->txbuflock, flags); + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + sc->curchan = sc->hw->conf.channel; + sc->curband = &sc->sbands[sc->curchan->band]; + sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; - bf->skb = skb; + ret = ath5k_reset(sc, NULL); + if (ret) + goto done; - if (ath5k_txbuf_setup(sc, bf, txq, padsize)) { - bf->skb = NULL; - spin_lock_irqsave(&sc->txbuflock, flags); - list_add_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock_irqrestore(&sc->txbuflock, flags); - goto drop_packet; + ath5k_rfkill_hw_start(ah); + + /* + * Reset the key cache since some parts do not reset the + * contents on initial power up or resume from suspend. + */ + for (i = 0; i < common->keymax; i++) + ath_hw_keyreset(common, (u16) i); + + ath5k_hw_set_ack_bitrate_high(ah, true); + ret = 0; +done: + mmiowb(); + mutex_unlock(&sc->lock); + return ret; +} + +static void stop_tasklets(struct ath5k_softc *sc) +{ + tasklet_kill(&sc->rxtq); + tasklet_kill(&sc->txtq); + tasklet_kill(&sc->calib); + tasklet_kill(&sc->beacontq); + tasklet_kill(&sc->ani_tasklet); +} + +/* + * Stop the device, grabbing the top-level lock to protect + * against concurrent entry through ath5k_init (which can happen + * if another thread does a system call and the thread doing the + * stop is preempted). + */ +static int +ath5k_stop_hw(struct ath5k_softc *sc) +{ + int ret; + + mutex_lock(&sc->lock); + ret = ath5k_stop_locked(sc); + if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { + /* + * Don't set the card in full sleep mode! + * + * a) When the device is in this state it must be carefully + * woken up or references to registers in the PCI clock + * domain may freeze the bus (and system). This varies + * by chip and is mostly an issue with newer parts + * (madwifi sources mentioned srev >= 0x78) that go to + * sleep more quickly. + * + * b) On older chips full sleep results a weird behaviour + * during wakeup. I tested various cards with srev < 0x78 + * and they don't wake up after module reload, a second + * module reload is needed to bring the card up again. + * + * Until we figure out what's going on don't enable + * full chip reset on any chip (this is what Legacy HAL + * and Sam's HAL do anyway). Instead Perform a full reset + * on the device (same as initial state after attach) and + * leave it idle (keep MAC/BB on warm reset) */ + ret = ath5k_hw_on_hold(sc->ah); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "putting device to sleep\n"); } - return NETDEV_TX_OK; + ath5k_txbuf_free_skb(sc, sc->bbuf); -drop_packet: - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + mmiowb(); + mutex_unlock(&sc->lock); + + stop_tasklets(sc); + + ath5k_rfkill_hw_stop(sc->ah); + + return ret; } /* @@ -3016,91 +2385,264 @@ static void ath5k_reset_work(struct work_struct *work) mutex_unlock(&sc->lock); } -static int ath5k_start(struct ieee80211_hw *hw) -{ - return ath5k_init(hw->priv); -} - -static void ath5k_stop(struct ieee80211_hw *hw) -{ - ath5k_stop_hw(hw->priv); -} - -static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int +ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); + u8 mac[ETH_ALEN] = {}; int ret; - mutex_lock(&sc->lock); - if (sc->vif) { - ret = 0; - goto end; - } - - sc->vif = vif; + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); - switch (vif->type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - sc->opmode = vif->type; - break; - default: - ret = -EOPNOTSUPP; - goto end; - } + /* + * Check if the MAC has multi-rate retry support. + * We do this by trying to setup a fake extended + * descriptor. MACs that don't have support will + * return false w/o doing anything. MACs that do + * support it will return true w/o doing anything. + */ + ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); + if (ret < 0) + goto err; + if (ret > 0) + __set_bit(ATH_STAT_MRRETRY, sc->status); - ath5k_hw_set_lladdr(sc->ah, vif->addr); - ath5k_mode_setup(sc); + /* + * Collect the channel list. The 802.11 layer + * is resposible for filtering this list based + * on settings like the phy mode and regulatory + * domain restrictions. + */ + ret = ath5k_setup_bands(hw); + if (ret) { + ATH5K_ERR(sc, "can't get channels\n"); + goto err; + } - ret = 0; -end: - mutex_unlock(&sc->lock); - return ret; -} + /* NB: setup here so ath5k_rate_update is happy */ + if (test_bit(AR5K_MODE_11A, ah->ah_modes)) + ath5k_setcurmode(sc, AR5K_MODE_11A); + else + ath5k_setcurmode(sc, AR5K_MODE_11B); -static void -ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ath5k_softc *sc = hw->priv; - u8 mac[ETH_ALEN] = {}; + /* + * Allocate tx+rx descriptors and populate the lists. + */ + ret = ath5k_desc_alloc(sc, pdev); + if (ret) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + goto err; + } - mutex_lock(&sc->lock); - if (sc->vif != vif) - goto end; + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that hw functions handle resetting + * these queues at the needed time. + */ + ret = ath5k_beaconq_setup(ah); + if (ret < 0) { + ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); + goto err_desc; + } + sc->bhalq = ret; + sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); + if (IS_ERR(sc->cabq)) { + ATH5K_ERR(sc, "can't setup cab queue\n"); + ret = PTR_ERR(sc->cabq); + goto err_bhal; + } - ath5k_hw_set_lladdr(sc->ah, mac); - sc->vif = NULL; -end: - mutex_unlock(&sc->lock); -} + sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); + if (IS_ERR(sc->txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(sc->txq); + goto err_queues; + } -/* - * TODO: Phy disable/diversity etc - */ -static int -ath5k_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - struct ieee80211_conf *conf = &hw->conf; - int ret = 0; + tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); + tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); + tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); + tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); + tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); - mutex_lock(&sc->lock); + INIT_WORK(&sc->reset_work, ath5k_reset_work); - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = ath5k_chan_set(sc, conf->channel); - if (ret < 0) - goto unlock; + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_queues; } - if ((changed & IEEE80211_CONF_CHANGE_POWER) && - (sc->power_level != conf->power_level)) { + SET_IEEE80211_PERM_ADDR(hw, mac); + /* All MAC address bits matter for ACKs */ + memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + + regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); + if (ret) { + ATH5K_ERR(sc, "can't initialize regulatory system\n"); + goto err_queues; + } + + ret = ieee80211_register_hw(hw); + if (ret) { + ATH5K_ERR(sc, "can't register ieee80211 hw\n"); + goto err_queues; + } + + if (!ath_is_world_regd(regulatory)) + regulatory_hint(hw->wiphy, regulatory->alpha2); + + ath5k_init_leds(sc); + + ath5k_sysfs_register(sc); + + return 0; +err_queues: + ath5k_txq_release(sc); +err_bhal: + ath5k_hw_release_tx_queue(ah, sc->bhalq); +err_desc: + ath5k_desc_free(sc, pdev); +err: + return ret; +} + +static void +ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * NB: the order of these is important: + * o call the 802.11 layer before detaching ath5k_hw to + * ensure callbacks into the driver to delete global + * key cache entries can be handled + * o reclaim the tx queue data structures after calling + * the 802.11 layer as we'll get called back to reclaim + * node state and potentially want to use them + * o to cleanup the tx queues the hal is called, so detach + * it last + * XXX: ??? detach ath5k_hw ??? + * Other than that, it's straightforward... + */ + ieee80211_unregister_hw(hw); + ath5k_desc_free(sc, pdev); + ath5k_txq_release(sc); + ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); + ath5k_unregister_leds(sc); + + ath5k_sysfs_unregister(sc); + /* + * NB: can't reclaim these until after ieee80211_ifdetach + * returns because we'll get called back to reclaim node + * state and potentially want to use them. + */ +} + +/********************\ +* Mac80211 functions * +\********************/ + +static int +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath5k_softc *sc = hw->priv; + + return ath5k_tx_queue(hw, skb, sc->txq); +} + +static int ath5k_start(struct ieee80211_hw *hw) +{ + return ath5k_init(hw->priv); +} + +static void ath5k_stop(struct ieee80211_hw *hw) +{ + ath5k_stop_hw(hw->priv); +} + +static int ath5k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath5k_softc *sc = hw->priv; + int ret; + + mutex_lock(&sc->lock); + if (sc->vif) { + ret = 0; + goto end; + } + + sc->vif = vif; + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + sc->opmode = vif->type; + break; + default: + ret = -EOPNOTSUPP; + goto end; + } + + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); + + ath5k_hw_set_lladdr(sc->ah, vif->addr); + ath5k_mode_setup(sc); + + ret = 0; +end: + mutex_unlock(&sc->lock); + return ret; +} + +static void +ath5k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath5k_softc *sc = hw->priv; + u8 mac[ETH_ALEN] = {}; + + mutex_lock(&sc->lock); + if (sc->vif != vif) + goto end; + + ath5k_hw_set_lladdr(sc->ah, mac); + sc->vif = NULL; +end: + mutex_unlock(&sc->lock); +} + +/* + * TODO: Phy disable/diversity etc + */ +static int +ath5k_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ieee80211_conf *conf = &hw->conf; + int ret = 0; + + mutex_lock(&sc->lock); + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = ath5k_chan_set(sc, conf->channel); + if (ret < 0) + goto unlock; + } + + if ((changed & IEEE80211_CONF_CHANGE_POWER) && + (sc->power_level != conf->power_level)) { sc->power_level = conf->power_level; /* Half dB steps */ @@ -3325,214 +2867,538 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = -EINVAL; } - mmiowb(); - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct ath5k_softc *sc = hw->priv; - - /* Force update */ - ath5k_hw_update_mib_counters(sc->ah); - - stats->dot11ACKFailureCount = sc->stats.ack_fail; - stats->dot11RTSFailureCount = sc->stats.rts_fail; - stats->dot11RTSSuccessCount = sc->stats.rts_ok; - stats->dot11FCSErrorCount = sc->stats.fcs_error; - - return 0; -} - -static int ath5k_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct ath5k_softc *sc = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; + mmiowb(); + mutex_unlock(&sc->lock); + return ret; +} + +static int +ath5k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ath5k_softc *sc = hw->priv; + + /* Force update */ + ath5k_hw_update_mib_counters(sc->ah); + + stats->dot11ACKFailureCount = sc->stats.ack_fail; + stats->dot11RTSFailureCount = sc->stats.rts_fail; + stats->dot11RTSSuccessCount = sc->stats.rts_ok; + stats->dot11FCSErrorCount = sc->stats.fcs_error; + + return 0; +} + +static int ath5k_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; + + survey->channel = conf->channel; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = sc->ah->ah_noise_floor; + + return 0; +} + +static u64 +ath5k_get_tsf(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + return ath5k_hw_get_tsf64(sc->ah); +} + +static void +ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +{ + struct ath5k_softc *sc = hw->priv; + + ath5k_hw_set_tsf64(sc->ah, tsf); +} + +static void +ath5k_reset_tsf(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * in IBSS mode we need to update the beacon timers too. + * this will also reset the TSF if we call it with 0 + */ + if (sc->opmode == NL80211_IFTYPE_ADHOC) + ath5k_beacon_update_timers(sc, 0); + else + ath5k_hw_reset_tsf(sc->ah); +} + +static void +set_beacon_filter(struct ieee80211_hw *hw, bool enable) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + u32 rfilt; + rfilt = ath5k_hw_get_rx_filter(ah); + if (enable) + rfilt |= AR5K_RX_FILTER_BEACON; + else + rfilt &= ~AR5K_RX_FILTER_BEACON; + ath5k_hw_set_rx_filter(ah, rfilt); + sc->filter_flags = rfilt; +} + +static void ath5k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + unsigned long flags; + + mutex_lock(&sc->lock); + if (WARN_ON(sc->vif != vif)) + goto unlock; + + if (changes & BSS_CHANGED_BSSID) { + /* Cache for later use during resets */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = 0; + ath5k_hw_set_bssid(ah); + mmiowb(); + } + + if (changes & BSS_CHANGED_BEACON_INT) + sc->bintval = bss_conf->beacon_int; + + if (changes & BSS_CHANGED_ASSOC) { + sc->assoc = bss_conf->assoc; + if (sc->opmode == NL80211_IFTYPE_STATION) + set_beacon_filter(hw, sc->assoc); + ath5k_hw_set_ledstate(sc->ah, sc->assoc ? + AR5K_LED_ASSOC : AR5K_LED_INIT); + if (bss_conf->assoc) { + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); + common->curaid = bss_conf->aid; + ath5k_hw_set_bssid(ah); + /* Once ANI is available you would start it here */ + } + } + + if (changes & BSS_CHANGED_BEACON) { + spin_lock_irqsave(&sc->block, flags); + ath5k_beacon_update(hw, vif); + spin_unlock_irqrestore(&sc->block, flags); + } + + if (changes & BSS_CHANGED_BEACON_ENABLED) + sc->enable_beacon = bss_conf->enable_beacon; + + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON_INT)) + ath5k_beacon_config(sc); + + unlock: + mutex_unlock(&sc->lock); +} + +static void ath5k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + if (!sc->assoc) + ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN); +} + +static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + ath5k_hw_set_ledstate(sc->ah, sc->assoc ? + AR5K_LED_ASSOC : AR5K_LED_INIT); +} + +/** + * ath5k_set_coverage_class - Set IEEE 802.11 coverage class + * + * @hw: struct ieee80211_hw pointer + * @coverage_class: IEEE 802.11 coverage class number + * + * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given + * coverage class. The values are persistent, they are restored after device + * reset. + */ +static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +{ + struct ath5k_softc *sc = hw->priv; + + mutex_lock(&sc->lock); + ath5k_hw_set_coverage_class(sc->ah, coverage_class); + mutex_unlock(&sc->lock); +} + +static const struct ieee80211_ops ath5k_hw_ops = { + .tx = ath5k_tx, + .start = ath5k_start, + .stop = ath5k_stop, + .add_interface = ath5k_add_interface, + .remove_interface = ath5k_remove_interface, + .config = ath5k_config, + .prepare_multicast = ath5k_prepare_multicast, + .configure_filter = ath5k_configure_filter, + .set_key = ath5k_set_key, + .get_stats = ath5k_get_stats, + .get_survey = ath5k_get_survey, + .conf_tx = NULL, + .get_tsf = ath5k_get_tsf, + .set_tsf = ath5k_set_tsf, + .reset_tsf = ath5k_reset_tsf, + .bss_info_changed = ath5k_bss_info_changed, + .sw_scan_start = ath5k_sw_scan_start, + .sw_scan_complete = ath5k_sw_scan_complete, + .set_coverage_class = ath5k_set_coverage_class, +}; + +/********************\ +* PCI Initialization * +\********************/ + +static int __devinit +ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath5k_softc *sc; + struct ath_common *common; + struct ieee80211_hw *hw; + int ret; + u8 csz; + + /* + * L0s needs to be disabled on all ath5k cards. + * + * For distributions shipping with CONFIG_PCIEASPM (this will be enabled + * by default in the future in 2.6.36) this will also mean both L1 and + * L0s will be disabled when a pre 1.1 PCIe device is detected. We do + * know L1 works correctly even for all ath5k pre 1.1 PCIe devices + * though but cannot currently undue the effect of a blacklist, for + * details you can read pcie_aspm_sanity_check() and see how it adjusts + * the device link capability. + * + * It may be possible in the future to implement some PCI API to allow + * drivers to override blacklists for pre 1.1 PCIe but for now it is + * best to accept that both L0s and L1 will be disabled completely for + * distributions shipping with CONFIG_PCIEASPM rather than having this + * issue present. Motivation for adding this new API will be to help + * with power consumption for some of these devices. + */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "can't enable device\n"); + goto err; + } + + /* XXX 32-bit addressing only */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "32-bit DMA not available\n"); + goto err_dis; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES >> 2; + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + */ + pci_write_config_byte(pdev, 0x41, 0); + + ret = pci_request_region(pdev, 0, "ath5k"); + if (ret) { + dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); + goto err_dis; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; + ret = -EIO; + goto err_reg; + } + + /* + * Allocate hw (mac80211 main struct) + * and hw->priv (driver private data) + */ + hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); + ret = -ENOMEM; + goto err_map; + } + + dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); + + /* Initialize driver private data */ + SET_IEEE80211_DEV(hw, &pdev->dev); + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + + hw->extra_tx_headroom = 2; + hw->channel_change_time = 5000; + sc = hw->priv; + sc->hw = hw; + sc->pdev = pdev; + + ath5k_debug_init_device(sc); + + /* + * Mark the device as detached to avoid processing + * interrupts until setup is complete. + */ + __set_bit(ATH_STAT_INVALID, sc->status); + + sc->iobase = mem; /* So we can unmap it on detach */ + sc->opmode = NL80211_IFTYPE_STATION; + sc->bintval = 1000; + mutex_init(&sc->lock); + spin_lock_init(&sc->rxbuflock); + spin_lock_init(&sc->txbuflock); + spin_lock_init(&sc->block); + + /* Set private data */ + pci_set_drvdata(pdev, sc); + + /* Setup interrupt handler */ + ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); + if (ret) { + ATH5K_ERR(sc, "request_irq failed\n"); + goto err_free; + } + + /* If we passed the test, malloc an ath5k_hw struct */ + sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); + if (!sc->ah) { + ret = -ENOMEM; + ATH5K_ERR(sc, "out of memory\n"); + goto err_irq; + } + + sc->ah->ah_sc = sc; + sc->ah->ah_iobase = sc->iobase; + common = ath5k_hw_common(sc->ah); + common->ops = &ath5k_common_ops; + common->ah = sc->ah; + common->hw = hw; + common->cachelsz = csz << 2; /* convert to bytes */ + + /* Initialize device */ + ret = ath5k_hw_attach(sc); + if (ret) { + goto err_free_ah; + } + + /* set up multi-rate retry capabilities */ + if (sc->ah->ah_version == AR5K_AR5212) { + hw->max_rates = 4; + hw->max_rate_tries = 11; + } + + /* Finish private driver data initialization */ + ret = ath5k_attach(pdev, hw); + if (ret) + goto err_ah; + + ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", + ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev), + sc->ah->ah_mac_srev, + sc->ah->ah_phy_revision); + + if (!sc->ah->ah_single_chip) { + /* Single chip radio (!RF5111) */ + if (sc->ah->ah_radio_5ghz_revision && + !sc->ah->ah_radio_2ghz_revision) { + /* No 5GHz support -> report 2GHz radio */ + if (!test_bit(AR5K_MODE_11A, + sc->ah->ah_capabilities.cap_mode)) { + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* No 2GHz support (5110 and some + * 5Ghz only cards) -> report 5Ghz radio */ + } else if (!test_bit(AR5K_MODE_11B, + sc->ah->ah_capabilities.cap_mode)) { + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* Multiband radio */ + } else { + ATH5K_INFO(sc, "RF%s multiband radio found" + " (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + } + } + /* Multi chip radio (RF5111 - RF2111) -> + * report both 2GHz/5GHz radios */ + else if (sc->ah->ah_radio_5ghz_revision && + sc->ah->ah_radio_2ghz_revision){ + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_2ghz_revision), + sc->ah->ah_radio_2ghz_revision); + } + } + - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = sc->ah->ah_noise_floor; + /* ready to process interrupts */ + __clear_bit(ATH_STAT_INVALID, sc->status); return 0; +err_ah: + ath5k_hw_detach(sc->ah); +err_free_ah: + kfree(sc->ah); +err_irq: + free_irq(pdev->irq, sc); +err_free: + ieee80211_free_hw(hw); +err_map: + pci_iounmap(pdev, mem); +err_reg: + pci_release_region(pdev, 0); +err_dis: + pci_disable_device(pdev); +err: + return ret; } -static u64 -ath5k_get_tsf(struct ieee80211_hw *hw) +static void __devexit +ath5k_pci_remove(struct pci_dev *pdev) { - struct ath5k_softc *sc = hw->priv; + struct ath5k_softc *sc = pci_get_drvdata(pdev); - return ath5k_hw_get_tsf64(sc->ah); + ath5k_debug_finish_device(sc); + ath5k_detach(pdev, sc->hw); + ath5k_hw_detach(sc->ah); + kfree(sc->ah); + free_irq(pdev->irq, sc); + pci_iounmap(pdev, sc->iobase); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + ieee80211_free_hw(sc->hw); } -static void -ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +#ifdef CONFIG_PM_SLEEP +static int ath5k_pci_suspend(struct device *dev) { - struct ath5k_softc *sc = hw->priv; + struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); - ath5k_hw_set_tsf64(sc->ah, tsf); + ath5k_led_off(sc); + return 0; } -static void -ath5k_reset_tsf(struct ieee80211_hw *hw) +static int ath5k_pci_resume(struct device *dev) { - struct ath5k_softc *sc = hw->priv; + struct pci_dev *pdev = to_pci_dev(dev); + struct ath5k_softc *sc = pci_get_drvdata(pdev); /* - * in IBSS mode we need to update the beacon timers too. - * this will also reset the TSF if we call it with 0 + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) - ath5k_beacon_update_timers(sc, 0); - else - ath5k_hw_reset_tsf(sc->ah); + pci_write_config_byte(pdev, 0x41, 0); + + ath5k_led_enable(sc); + return 0; } +static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); +#define ATH5K_PM_OPS (&ath5k_pm_ops) +#else +#define ATH5K_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static struct pci_driver ath5k_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ath5k_pci_id_table, + .probe = ath5k_pci_probe, + .remove = __devexit_p(ath5k_pci_remove), + .driver.pm = ATH5K_PM_OPS, +}; + /* - * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, - * this is called only once at config_bss time, for AP we do it every - * SWBA interrupt so that the TIM will reflect buffered frames. - * - * Called with the beacon lock. + * Module init/exit functions */ -static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +static int __init +init_ath5k_pci(void) { int ret; - struct ath5k_softc *sc = hw->priv; - struct sk_buff *skb; - - if (WARN_ON(!vif)) { - ret = -EINVAL; - goto out; - } - - skb = ieee80211_beacon_get(hw, vif); - - if (!skb) { - ret = -ENOMEM; - goto out; - } - - ath5k_debug_dump_skb(sc, skb, "BC ", 1); - - ath5k_txbuf_free_skb(sc, sc->bbuf); - sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf); - if (ret) - sc->bbuf->skb = NULL; -out: - return ret; -} - -static void -set_beacon_filter(struct ieee80211_hw *hw, bool enable) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - u32 rfilt; - rfilt = ath5k_hw_get_rx_filter(ah); - if (enable) - rfilt |= AR5K_RX_FILTER_BEACON; - else - rfilt &= ~AR5K_RX_FILTER_BEACON; - ath5k_hw_set_rx_filter(ah, rfilt); - sc->filter_flags = rfilt; -} - -static void ath5k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - struct ath_common *common = ath5k_hw_common(ah); - unsigned long flags; - - mutex_lock(&sc->lock); - if (WARN_ON(sc->vif != vif)) - goto unlock; - - if (changes & BSS_CHANGED_BSSID) { - /* Cache for later use during resets */ - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = 0; - ath5k_hw_set_bssid(ah); - mmiowb(); - } - - if (changes & BSS_CHANGED_BEACON_INT) - sc->bintval = bss_conf->beacon_int; - if (changes & BSS_CHANGED_ASSOC) { - sc->assoc = bss_conf->assoc; - if (sc->opmode == NL80211_IFTYPE_STATION) - set_beacon_filter(hw, sc->assoc); - ath5k_hw_set_ledstate(sc->ah, sc->assoc ? - AR5K_LED_ASSOC : AR5K_LED_INIT); - if (bss_conf->assoc) { - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, - "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - common->curaid = bss_conf->aid; - ath5k_hw_set_bssid(ah); - /* Once ANI is available you would start it here */ - } - } + ath5k_debug_init(); - if (changes & BSS_CHANGED_BEACON) { - spin_lock_irqsave(&sc->block, flags); - ath5k_beacon_update(hw, vif); - spin_unlock_irqrestore(&sc->block, flags); + ret = pci_register_driver(&ath5k_pci_driver); + if (ret) { + printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); + return ret; } - if (changes & BSS_CHANGED_BEACON_ENABLED) - sc->enable_beacon = bss_conf->enable_beacon; - - if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | - BSS_CHANGED_BEACON_INT)) - ath5k_beacon_config(sc); - - unlock: - mutex_unlock(&sc->lock); + return 0; } -static void ath5k_sw_scan_start(struct ieee80211_hw *hw) +static void __exit +exit_ath5k_pci(void) { - struct ath5k_softc *sc = hw->priv; - if (!sc->assoc) - ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN); -} + pci_unregister_driver(&ath5k_pci_driver); -static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - ath5k_hw_set_ledstate(sc->ah, sc->assoc ? - AR5K_LED_ASSOC : AR5K_LED_INIT); + ath5k_debug_finish(); } -/** - * ath5k_set_coverage_class - Set IEEE 802.11 coverage class - * - * @hw: struct ieee80211_hw pointer - * @coverage_class: IEEE 802.11 coverage class number - * - * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given - * coverage class. The values are persistent, they are restored after device - * reset. - */ -static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) -{ - struct ath5k_softc *sc = hw->priv; - - mutex_lock(&sc->lock); - ath5k_hw_set_coverage_class(sc->ah, coverage_class); - mutex_unlock(&sc->lock); -} +module_init(init_ath5k_pci); +module_exit(exit_ath5k_pci);