diff options
author | David S. Miller <davem@davemloft.net> | 2009-06-20 12:16:40 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-20 12:16:40 +0400 |
commit | c3da63f35773b04e885c5659e560d5c521d2682e (patch) | |
tree | 5e876e7587f299cadce0b53bfaf912fb28d8283d /drivers/net | |
parent | 73e42897e8e5619eacb787d2ce69be12f47cfc21 (diff) | |
parent | a97f4424fb4cddecf9b13c9b0e3f79924b624a7f (diff) | |
download | linux-c3da63f35773b04e885c5659e560d5c521d2682e.tar.xz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/iwm.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/netdev.c | 49 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/sdio.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 1 |
9 files changed, 136 insertions, 31 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 55f7de09d134..ea045151f953 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -538,6 +538,7 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->iobase = mem; /* So we can unmap it on detach */ sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; + sc->bintval = 1000; mutex_init(&sc->lock); spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); @@ -686,6 +687,13 @@ ath5k_pci_resume(struct pci_dev *pdev) if (err) return err; + /* + * 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); + err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); if (err) { ATH5K_ERR(sc, "request_irq failed\n"); @@ -2748,9 +2756,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, goto end; } - /* Set to a reasonable value. Note that this will - * be set to mac80211's value at ath5k_config(). */ - sc->bintval = 1000; ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); ret = 0; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9f49a3251d4d..66a6c1f5022a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1196,8 +1196,8 @@ void ath_radio_disable(struct ath_softc *sc) ath9k_hw_phy_disable(ah); ath9k_hw_configpcipowersave(ah, 1); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); ath9k_ps_restore(sc); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); } /*******************/ diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index ccdf20a2e9be..170c5b32e49b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -87,6 +87,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; + u32 val; int ret = 0; struct ath_hw *ah; @@ -133,6 +134,14 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + ret = pci_request_region(pdev, 0, "ath9k"); if (ret) { dev_err(&pdev->dev, "PCI memory region reserve error\n"); @@ -239,12 +248,21 @@ static int ath_pci_resume(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + u32 val; int err; err = pci_enable_device(pdev); if (err) return err; pci_restore_state(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_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); /* Enable LED */ ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f99f3a76df3f..cece1c4c6bda 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -539,11 +539,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (ath_beacon_dtim_pending_cab(skb)) { /* * Remain awake waiting for buffered broadcast/multicast - * frames. + * frames. If the last broadcast/multicast frame is not + * received properly, the next beacon frame will work as + * a backup trigger for returning into NETWORK SLEEP state, + * so we are waiting for it as well. */ DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " "buffered broadcast/multicast frame(s)\n"); - sc->sc_flags |= SC_OP_WAIT_FOR_CAB; + sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; return; } diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 635c16ee6186..77c339f8516c 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -288,6 +288,7 @@ struct iwm_priv { u8 *eeprom; struct timer_list watchdog; struct work_struct reset_worker; + struct mutex mutex; struct rfkill *rfkill; char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); @@ -315,8 +316,11 @@ extern const struct iw_handler_def iwm_iw_handler_def; void *iwm_if_alloc(int sizeof_bus, struct device *dev, struct iwm_if_ops *if_ops); void iwm_if_free(struct iwm_priv *iwm); +int iwm_if_add(struct iwm_priv *iwm); +void iwm_if_remove(struct iwm_priv *iwm); int iwm_mode_to_nl80211_iftype(int mode); int iwm_priv_init(struct iwm_priv *iwm); +void iwm_priv_deinit(struct iwm_priv *iwm); void iwm_reset(struct iwm_priv *iwm); void iwm_tx_credit_init_pools(struct iwm_priv *iwm, struct iwm_umac_notif_alive *alive); diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6a2640f16b6d..8be206d58222 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -112,6 +112,9 @@ static void iwm_statistics_request(struct work_struct *work) iwm_send_umac_stats_req(iwm, 0); } +int __iwm_up(struct iwm_priv *iwm); +int __iwm_down(struct iwm_priv *iwm); + static void iwm_reset_worker(struct work_struct *work) { struct iwm_priv *iwm; @@ -120,6 +123,19 @@ static void iwm_reset_worker(struct work_struct *work) iwm = container_of(work, struct iwm_priv, reset_worker); + /* + * XXX: The iwm->mutex is introduced purely for this reset work, + * because the other users for iwm_up and iwm_down are only netdev + * ndo_open and ndo_stop which are already protected by rtnl. + * Please remove iwm->mutex together if iwm_reset_worker() is not + * required in the future. + */ + if (!mutex_trylock(&iwm->mutex)) { + IWM_WARN(iwm, "We are in the middle of interface bringing " + "UP/DOWN. Skip driver resetting.\n"); + return; + } + if (iwm->umac_profile_active) { profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); if (profile) @@ -128,10 +144,10 @@ static void iwm_reset_worker(struct work_struct *work) IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); } - iwm_down(iwm); + __iwm_down(iwm); while (retry++ < 3) { - ret = iwm_up(iwm); + ret = __iwm_up(iwm); if (!ret) break; @@ -142,7 +158,7 @@ static void iwm_reset_worker(struct work_struct *work) IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); kfree(profile); - return; + goto out; } if (profile) { @@ -151,6 +167,9 @@ static void iwm_reset_worker(struct work_struct *work) iwm_send_mlme_profile(iwm); kfree(profile); } + + out: + mutex_unlock(&iwm->mutex); } static void iwm_watchdog(unsigned long data) @@ -215,10 +234,21 @@ int iwm_priv_init(struct iwm_priv *iwm) init_timer(&iwm->watchdog); iwm->watchdog.function = iwm_watchdog; iwm->watchdog.data = (unsigned long)iwm; + mutex_init(&iwm->mutex); return 0; } +void iwm_priv_deinit(struct iwm_priv *iwm) +{ + int i; + + for (i = 0; i < IWM_TX_QUEUES; i++) + destroy_workqueue(iwm->txq[i].wq); + + destroy_workqueue(iwm->rx_wq); +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -466,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm) iwm_rx_free(iwm); - cancel_delayed_work(&iwm->stats_request); + cancel_delayed_work_sync(&iwm->stats_request); memset(wstats, 0, sizeof(struct iw_statistics)); wstats->qual.updated = IW_QUAL_ALL_INVALID; @@ -511,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm) return 0; } -int iwm_up(struct iwm_priv *iwm) +int __iwm_up(struct iwm_priv *iwm) { int ret; struct iwm_notif *notif_reboot, *notif_ack = NULL; @@ -647,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm) return -EIO; } -int iwm_down(struct iwm_priv *iwm) +int iwm_up(struct iwm_priv *iwm) +{ + int ret; + + mutex_lock(&iwm->mutex); + ret = __iwm_up(iwm); + mutex_unlock(&iwm->mutex); + + return ret; +} + +int __iwm_down(struct iwm_priv *iwm) { int ret; @@ -678,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm) return 0; } + +int iwm_down(struct iwm_priv *iwm) +{ + int ret; + + mutex_lock(&iwm->mutex); + ret = __iwm_down(iwm); + mutex_unlock(&iwm->mutex); + + return ret; +} diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index 68e2c3b6c7a1..aaa20c6885c8 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -114,32 +114,31 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, iwm = wdev_to_iwm(wdev); iwm->bus_ops = if_ops; iwm->wdev = wdev; - iwm_priv_init(iwm); + + ret = iwm_priv_init(iwm); + if (ret) { + dev_err(dev, "failed to init iwm_priv\n"); + goto out_wdev; + } + wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); - ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, - IWM_TX_QUEUES); + ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); if (!ndev) { dev_err(dev, "no memory for network device instance\n"); - goto out_wdev; + goto out_priv; } ndev->netdev_ops = &iwm_netdev_ops; ndev->wireless_handlers = &iwm_iw_handler_def; ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - ret = register_netdev(ndev); - if (ret < 0) { - dev_err(dev, "Failed to register netdev: %d\n", ret); - goto out_ndev; - } - wdev->netdev = ndev; return iwm; - out_ndev: - free_netdev(ndev); + out_priv: + iwm_priv_deinit(iwm); out_wdev: iwm_wdev_free(iwm); @@ -148,15 +147,29 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, void iwm_if_free(struct iwm_priv *iwm) { - int i; - if (!iwm_to_ndev(iwm)) return; - unregister_netdev(iwm_to_ndev(iwm)); free_netdev(iwm_to_ndev(iwm)); iwm_wdev_free(iwm); - destroy_workqueue(iwm->rx_wq); - for (i = 0; i < IWM_TX_QUEUES; i++) - destroy_workqueue(iwm->txq[i].wq); + iwm_priv_deinit(iwm); +} + +int iwm_if_add(struct iwm_priv *iwm) +{ + struct net_device *ndev = iwm_to_ndev(iwm); + int ret; + + ret = register_netdev(ndev); + if (ret < 0) { + dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret); + return ret; + } + + return 0; +} + +void iwm_if_remove(struct iwm_priv *iwm) +{ + unregister_netdev(iwm_to_ndev(iwm)); } diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index b54da677b371..916681837fd2 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -454,10 +454,18 @@ static int iwm_sdio_probe(struct sdio_func *func, INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); + ret = iwm_if_add(iwm); + if (ret) { + dev_err(dev, "add SDIO interface failed\n"); + goto destroy_wq; + } + dev_info(dev, "IWM SDIO probe\n"); return 0; + destroy_wq: + destroy_workqueue(hw->isr_wq); debugfs_exit: iwm_debugfs_exit(iwm); if_free: @@ -471,9 +479,10 @@ static void iwm_sdio_remove(struct sdio_func *func) struct iwm_priv *iwm = hw_to_iwm(hw); struct device *dev = &func->dev; + iwm_if_remove(iwm); + destroy_workqueue(hw->isr_wq); iwm_debugfs_exit(iwm); iwm_if_free(iwm); - destroy_workqueue(hw->isr_wq); sdio_set_drvdata(func, NULL); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index f0e5e943f6e3..14a19baff214 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -67,6 +67,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, |