On Fri, Oct 8, 2010 at 1:12 PM, Jonathan Guerin <jonathan@xxxxxxxxxxxx> wrote: > On Thu, Oct 7, 2010 at 4:22 PM, Bruno Randolf <br1@xxxxxxxxxxx> wrote: >> On Thu October 7 2010 14:41:18 Jonathan Guerin wrote: >>> > I seem to be getting a kernel panic when creating an IBSS with the >>> > latest ath5k driver. I remember Bruno submitting patches recently >>> > which modifies the behaviour of timestamps in ath5k, so I was >>> > wondering if this was related. >> >> did i? ;) i don't remember that. >> >>> Correction, this is not when creating an IBSS, but when bringing up an >>> interface in monitor-mode. >> >> hmm... i don't see that with current wireless-testing. how do you create your >> monitor interface? > > iw dev wlan0 interface add mon0 type monitor > ifconfig mon0 up >> >> bruno >> >> > > I've just tried the latest wireless-testing build (2.6.36-rc7) on two > different machines with different hardware configurations (but both > with ath5k). I get the same kernel panic, repeatable every time I > bring up a monitor mode interface (or not long after, as soon as it > sees traffic). > > I reverted the kernels to 2.6.35 and this crash no longer happens. I'm > not sure if this is related to the 'rx memory clobbering' post, so I > haven't gone and tainted it. I'm happy to provide more data if > necessary. I've just looked for changes in ath5k which were submitted after 2.6.35 was released and found this patch. I won't pretend to understand what's been changed, but could it be causing the panics I'm observing? Thanks, Jonathan Guerin On Fri, Sep 17, 2010 at 1:45 PM, Bruno Randolf <br1@xxxxxxxxxxx> wrote: > From: Bob Copeland <me@xxxxxxxxxxxxxxx> > > 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 <me@xxxxxxxxxxxxxxx> > Signed-off-by: Bruno Randolf <br1@xxxxxxxxxxx> > > --- > Bruno: rebased to wireless-next > v2: resent because i lost the subject line before > --- > drivers/net/wireless/ath/ath5k/base.c | 1662 +++++++++++++++------------------ > 1 files changed, 764 insertions(+), 898 deletions(-) > > diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c > index f8c699d..9e4636f 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,299 +269,6 @@ 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) > -{ > - 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); > - } > - } > - > - > - /* 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 void __devexit > -ath5k_pci_remove(struct pci_dev *pdev) > -{ > - struct ath5k_softc *sc = pci_get_drvdata(pdev); > - > - 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); > -} > - > -#ifdef CONFIG_PM_SLEEP > -static int ath5k_pci_suspend(struct device *dev) > -{ > - struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); > - > - 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); > - > - /* > - * 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 > - */ > - pci_write_config_byte(pdev, 0x41, 0); > - > - ath5k_led_enable(sc); > - return 0; > -} > -#endif /* CONFIG_PM_SLEEP */ > - > - > /***********************\ > * Driver Initialization * > \***********************/ > @@ -772,170 +282,6 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re > return ath_reg_notifier_apply(wiphy, request, regulatory); > } > > -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; > - > - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); > - > - /* > - * 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 (ret < 0) > - goto err; > - if (ret > 0) > - __set_bit(ATH_STAT_MRRETRY, sc->status); > - > - /* > - * 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; > - } > - > - /* 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); > - > - /* > - * 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; > - } > - > - /* > - * 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; > - } > - > - 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; > - } > - > - 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; > - } > - > - 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. > - */ > -} > - > - > - > - > /********************\ > * Channel/mode setup * > \********************/ > @@ -1494,9 +840,6 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) > } > > > - > - > - > /**************\ > * Queues setup * > \**************/ > @@ -1696,8 +1039,6 @@ ath5k_txq_release(struct ath5k_softc *sc) > } > > > - > - > /*************\ > * RX Handling * > \*************/ > @@ -2121,6 +1462,59 @@ unlock: > * TX Handling * > \*************/ > > +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; > + > + ath5k_debug_dump_skb(sc, skb, "TX ", 1); > + > + /* > + * 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; > + } > + > + 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); > + > + 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; > + > +drop_packet: > + dev_kfree_skb_any(skb); > + return NETDEV_TX_OK; > +} > + > + > static void > ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) > { > @@ -2313,6 +1707,43 @@ err_unmap: > } > > /* > + * 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 > * also adjusted based on current state. > @@ -2389,7 +1820,6 @@ ath5k_beacon_send(struct ath5k_softc *sc) > sc->bsent++; > } > > - > /** > * ath5k_beacon_update_timers - update beacon timers > * > @@ -2491,7 +1921,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 > * > @@ -2570,156 +1999,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) > { > @@ -2882,68 +2161,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; > } > > /* > @@ -3020,6 +2389,179 @@ static void ath5k_reset_work(struct work_struct *work) > mutex_unlock(&sc->lock); > } > > +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; > + > + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); > + > + /* > + * 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 (ret < 0) > + goto err; > + if (ret > 0) > + __set_bit(ATH_STAT_MRRETRY, sc->status); > + > + /* > + * 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; > + } > + > + /* 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); > + > + /* > + * 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; > + } > + > + /* > + * 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; > + } > + > + 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; > + } > + > + 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; > + } > + > + 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); > @@ -3398,43 +2940,6 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) > ath5k_hw_reset_tsf(sc->ah); > } > > -/* > - * 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; > -} > - > static void > set_beacon_filter(struct ieee80211_hw *hw, bool enable) > { > @@ -3540,3 +3045,364 @@ static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) > 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); > + } > + } > + > + > + /* 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 void __devexit > +ath5k_pci_remove(struct pci_dev *pdev) > +{ > + struct ath5k_softc *sc = pci_get_drvdata(pdev); > + > + 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); > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int ath5k_pci_suspend(struct device *dev) > +{ > + struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); > + > + 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); > + > + /* > + * 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 > + */ > + 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, > +}; > + > +/* > + * 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); > > > Thanks, > > Jonathan > >>> > [ 54.501954] skb_under_panic: text:c04e27f2 len:110 put:14 he0 >>> > [ 54.507979] ------------[ cut here ]------------ >>> > [ 54.511864] kernel BUG at net/core/skbuff.c:146! >>> > [ 54.511864] invalid opcode: 0000 [#1] SMP >>> > [ 54.511864] last sysfs file: >>> > /sys/devices/pci0000:00/0000:00:0c.0/device [ 54.511864] Modules >>> > linked in: ath5k ath mac80211 led_class nfs lockd nfs_ac] [ 54.511864] >>> > [ 54.511864] Pid: 0, comm: swapper Not tainted 2.6.36-rc6-wl-wl+ #3 / >>> > [ 54.511864] EIP: 0060:[<c04c2b90>] EFLAGS: 00010286 CPU: 0 >>> > [ 54.511864] EIP is at skb_push+0x80/0x90 >>> > [ 54.511864] EAX: 00000087 EBX: c04e27f2 ECX: c079daf4 EDX: 00000000 >>> > [ 54.511864] ESI: cfd62cc0 EDI: cf468910 EBP: c0791d64 ESP: c0791d3c >>> > [ 54.511864] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 >>> > [ 54.511864] Process swapper (pid: 0, ti=c0790000 task=c07976a0 >>> > task.ti=c0790) [ 54.511864] Stack: >>> > [ 54.511864] c0754518 c04e27f2 0000006e 0000000e cfee8a00 cfee89f2 >>> > cfee8a60 0 [ 54.511864] <0> ce56c000 cfd62cc0 c0791d78 c04e27f2 >>> > cfd62cc0 cfd62cc0 cf46890 [ 54.511864] <0> c04cc866 00000040 cf4682c0 >>> > cf4682c0 cf4682c0 c0791df8 d0c06a0 [ 54.511864] Call Trace: >>> > [ 54.511864] [<c04e27f2>] ? skb_defer_rx_timestamp+0x22/0x80 >>> > [ 54.511864] [<c04e27f2>] ? skb_defer_rx_timestamp+0x22/0x80 >>> > [ 54.511864] [<c04cc866>] ? netif_receive_skb+0x26/0x90 >>> > [ 54.511864] [<d0c06a83>] ? ieee80211_rx+0x613/0x800 [mac80211] >>> > [ 54.511864] [<c04c33dc>] ? __alloc_skb+0x5c/0x110 >>> > [ 54.511864] [<d0c8badf>] ? ath5k_rx_skb_alloc+0x7f/0x160 [ath5k] >>> > [ 54.511864] [<d0c8cfa5>] ? ath5k_tasklet_rx+0x315/0x860 [ath5k] >>> > [ 54.511864] [<c0108538>] ? sched_clock+0x8/0x10 >>> > [ 54.511864] [<c016d885>] ? sched_clock_local+0xa5/0x180 >>> > [ 54.511864] [<d0c818c0>] ? ath5k_hw_get_isr+0xa0/0x380 [ath5k] >>> > [ 54.511864] [<d0c8ca9e>] ? ath5k_intr+0x2ae/0x4a0 [ath5k] >>> > [ 54.511864] [<c014fc17>] ? tasklet_action+0xa7/0xb0 >>> > [ 54.511864] [<c015095c>] ? __do_softirq+0x9c/0x1b0 >>> > [ 54.511864] [<c012c868>] ? default_spin_lock_flags+0x8/0x10 >>> > [ 54.511864] [<c05b927f>] ? _raw_spin_lock_irqsave+0x2f/0x50 >>> > [ 54.511864] [<c0150ab5>] ? do_softirq+0x45/0x50 >>> > [ 54.511864] [<c0150c25>] ? irq_exit+0x65/0x70 >>> > [ 54.511864] [<c05c0055>] ? do_IRQ+0x55/0xc0 >>> > [ 54.511864] [<c017112f>] ? ktime_get+0x6f/0x110 >>> > [ 54.511864] [<c01035b0>] ? common_interrupt+0x30/0x40 >>> > [ 54.511864] [<c012bcaa>] ? native_safe_halt+0xa/0x10 >>> > [ 54.511864] [<c0109f53>] ? default_idle+0x53/0xb0 >>> > [ 54.511864] [<c0101e4a>] ? cpu_idle+0x8a/0xf0 >>> > [ 54.511864] [<c05a2ccd>] ? rest_init+0x5d/0x70 >>> > [ 54.511864] [<c07d297b>] ? start_kernel+0x357/0x35d >>> > [ 54.511864] [<c07d2450>] ? unknown_bootoption+0x0/0x19e >>> > [ 54.511864] [<c07d20de>] ? i386_start_kernel+0xde/0xe6 >>> > [ 54.511864] Code: 00 00 89 4c 24 14 8b 88 ac 00 00 00 89 54 24 0c 89 >>> > 4c 24 1 [ 54.511864] EIP: [<c04c2b90>] skb_push+0x80/0x90 SS:ESP >>> > 0068:c0791d3c [ 54.511864] ---[ end trace ccaff68ea5123ae2 ]--- >>> > [ 54.513037] Kernel panic - not syncing: Fatal exception in interrupt >>> > [ 54.520124] Pid: 0, comm: swapper Tainted: G D >>> > 2.6.36-rc6-wl-wl+ #3 [ 54.521277] Call Trace: >>> > [ 54.524656] [<c05b6936>] ? printk+0x1d/0x1f >>> > [ 54.529491] [<c05b6817>] panic+0x5c/0x15e >>> > [ 54.533818] [<c05babdd>] oops_end+0xcd/0xd0 >>> > [ 54.538655] [<c0105ce4>] die+0x54/0x80 >>> > [ 54.542199] [<c05ba286>] do_trap+0x96/0xc0 >>> > [ 54.546781] [<c0103d10>] ? do_invalid_op+0x0/0xa0 >>> > [ 54.549181] [<c0103d9b>] do_invalid_op+0x8b/0xa0 >>> > [ 54.555342] [<c04c2b90>] ? skb_push+0x80/0x90 >>> > [ 54.556724] [<c014b041>] ? vprintk+0x191/0x3f0 >>> > [ 54.562339] [<c04e27f2>] ? skb_defer_rx_timestamp+0x22/0x80 >>> > [ 54.567341] [<c05ba017>] error_code+0x67/0x70 >>> > [ 54.568699] [<c04e27f2>] ? skb_defer_rx_timestamp+0x22/0x80 >>> > [ 54.573704] [<c04c2b90>] ? skb_push+0x80/0x90 >>> > [ 54.579064] [<c04e27f2>] ? skb_defer_rx_timestamp+0x22/0x80 >>> > [ 54.584082] [<c04e27f2>] skb_defer_rx_timestamp+0x22/0x80 >>> > [ 54.588612] [<c04cc866>] netif_receive_skb+0x26/0x90 >>> > [ 54.595838] [<d0c06a83>] ieee80211_rx+0x613/0x800 [mac80211] >>> > [ 54.597099] [<c04c33dc>] ? __alloc_skb+0x5c/0x110 >>> > [ 54.603523] [<d0c8badf>] ? ath5k_rx_skb_alloc+0x7f/0x160 [ath5k] >>> > [ 54.605849] [<d0c8cfa5>] ath5k_tasklet_rx+0x315/0x860 [ath5k] >>> > [ 54.611392] [<c0108538>] ? sched_clock+0x8/0x10 >>> > [ 54.613284] [<c016d885>] ? sched_clock_local+0xa5/0x180 >>> > [ 54.617265] [<d0c818c0>] ? ath5k_hw_get_isr+0xa0/0x380 [ath5k] >>> > [ 54.623076] [<d0c8ca9e>] ? ath5k_intr+0x2ae/0x4a0 [ath5k] >>> > [ 54.627564] [<c014fc17>] tasklet_action+0xa7/0xb0 >>> > [ 54.629963] [<c015095c>] __do_softirq+0x9c/0x1b0 >>> > [ 54.636107] [<c012c868>] ? default_spin_lock_flags+0x8/0x10 >>> > [ 54.637124] [<c05b927f>] ? _raw_spin_lock_irqsave+0x2f/0x50 >>> > [ 54.642137] [<c0150ab5>] do_softirq+0x45/0x50 >>> > [ 54.647499] [<c0150c25>] irq_exit+0x65/0x70 >>> > [ 54.652340] [<c05c0055>] do_IRQ+0x55/0xc0 >>> > [ 54.652664] [<c017112f>] ? ktime_get+0x6f/0x110 >>> > [ 54.658547] [<c01035b0>] common_interrupt+0x30/0x40 >>> > [ 54.661471] [<c012bcaa>] ? native_safe_halt+0xa/0x10 >>> > [ 54.664668] [<c0109f53>] default_idle+0x53/0xb0 >>> > [ 54.670559] [<c0101e4a>] cpu_idle+0x8a/0xf0 >>> > [ 54.675405] [<c05a2ccd>] rest_init+0x5d/0x70 >>> > [ 54.680506] [<c07d297b>] start_kernel+0x357/0x35d >>> > [ 54.682907] [<c07d2450>] ? unknown_bootoption+0x0/0x19e >>> > [ 54.686869] [<c07d20de>] i386_start_kernel+0xde/0xe6 >>> > >>> > Branch information: >>> > commit 25de059bdad7ce916df6f2cfdfc1c2d2d72abf11 >>> > Merge: 412d5af 46bf695 >>> > Author: John W. Linville <linville@xxxxxxxxxxxxx> >>> > Date: Tue Oct 5 15:09:33 2010 -0400 >>> > >>> > Thanks, >>> > >>> > Jonathan Guerin >>> >>> _______________________________________________ >>> ath5k-devel mailing list >>> ath5k-devel@xxxxxxxxxxxxxxx >>> https://lists.ath5k.org/mailman/listinfo/ath5k-devel >> > -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html