diff options
Diffstat (limited to 'drivers/net/wireless')
23 files changed, 339 insertions, 280 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 698d5672a07..dc5018a6d9e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5255,7 +5255,8 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key, WepKeyRid wkr; int rc; - WARN_ON(keylen == 0); + if (WARN_ON(keylen == 0)) + return -1; memset(&wkr, 0, sizeof(wkr)); wkr.len = cpu_to_le16(sizeof(wkr)); diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 8c8ce67971e..dc662b76a1c 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -166,6 +166,7 @@ struct ar9170 { struct ath_common common; struct mutex mutex; enum ar9170_device_state state; + bool registered; unsigned long bad_hw_nagger; int (*open)(struct ar9170 *); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 08dc42da0f6..257c734733d 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2701,7 +2701,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", wiphy_name(ar->hw->wiphy)); - return err; + ar->registered = true; + return 0; err_unreg: ieee80211_unregister_hw(ar->hw); @@ -2712,11 +2713,14 @@ err_out: void ar9170_unregister(struct ar9170 *ar) { + if (ar->registered) { #ifdef CONFIG_AR9170_LEDS - ar9170_unregister_leds(ar); + ar9170_unregister_leds(ar); #endif /* CONFIG_AR9170_LEDS */ - kfree_skb(ar->rx_failover); ieee80211_unregister_hw(ar->hw); + } + + kfree_skb(ar->rx_failover); mutex_destroy(&ar->mutex); } diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 0f361186b78..4e30197afff 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -582,43 +582,6 @@ static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, return 0; } -static int ar9170_usb_request_firmware(struct ar9170_usb *aru) -{ - int err = 0; - - err = request_firmware(&aru->firmware, "ar9170.fw", - &aru->udev->dev); - if (!err) { - aru->init_values = NULL; - return 0; - } - - if (aru->req_one_stage_fw) { - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found and is required for this device\n"); - return -EINVAL; - } - - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found, trying old firmware...\n"); - - err = request_firmware(&aru->init_values, "ar9170-1.fw", - &aru->udev->dev); - if (err) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - return err; - } - - err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); - if (err) { - release_firmware(aru->init_values); - dev_err(&aru->udev->dev, "firmware file not found.\n"); - return err; - } - - return err; -} - static int ar9170_usb_reset(struct ar9170_usb *aru) { int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); @@ -757,6 +720,103 @@ err_out: return err; } +static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) +{ + struct device *parent = aru->udev->dev.parent; + + /* unbind anything failed */ + if (parent) + down(&parent->sem); + device_release_driver(&aru->udev->dev); + if (parent) + up(&parent->sem); +} + +static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) +{ + struct ar9170_usb *aru = context; + int err; + + aru->firmware = fw; + + if (!fw) { + dev_err(&aru->udev->dev, "firmware file not found.\n"); + goto err_freefw; + } + + err = ar9170_usb_init_device(aru); + if (err) + goto err_freefw; + + err = ar9170_usb_open(&aru->common); + if (err) + goto err_unrx; + + err = ar9170_register(&aru->common, &aru->udev->dev); + + ar9170_usb_stop(&aru->common); + if (err) + goto err_unrx; + + return; + + err_unrx: + ar9170_usb_cancel_urbs(aru); + + err_freefw: + ar9170_usb_firmware_failed(aru); +} + +static void ar9170_usb_firmware_inits(const struct firmware *fw, + void *context) +{ + struct ar9170_usb *aru = context; + int err; + + if (!fw) { + dev_err(&aru->udev->dev, "file with init values not found.\n"); + ar9170_usb_firmware_failed(aru); + return; + } + + aru->init_values = fw; + + /* ok so we have the init values -- get code for two-stage */ + + err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", + &aru->udev->dev, GFP_KERNEL, aru, + ar9170_usb_firmware_finish); + if (err) + ar9170_usb_firmware_failed(aru); +} + +static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) +{ + struct ar9170_usb *aru = context; + int err; + + if (fw) { + ar9170_usb_firmware_finish(fw, context); + return; + } + + if (aru->req_one_stage_fw) { + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found and is required for this device\n"); + ar9170_usb_firmware_failed(aru); + return; + } + + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found, trying old firmware...\n"); + + err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", + &aru->udev->dev, GFP_KERNEL, aru, + ar9170_usb_firmware_inits); + if (err) + ar9170_usb_firmware_failed(aru); +} + static bool ar9170_requires_one_stage(const struct usb_device_id *id) { if (!id->driver_info) @@ -814,33 +874,9 @@ static int ar9170_usb_probe(struct usb_interface *intf, if (err) goto err_freehw; - err = ar9170_usb_request_firmware(aru); - if (err) - goto err_freehw; - - err = ar9170_usb_init_device(aru); - if (err) - goto err_freefw; - - err = ar9170_usb_open(ar); - if (err) - goto err_unrx; - - err = ar9170_register(ar, &udev->dev); - - ar9170_usb_stop(ar); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_freefw: - release_firmware(aru->init_values); - release_firmware(aru->firmware); - + return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", + &aru->udev->dev, GFP_KERNEL, aru, + ar9170_usb_firmware_step2); err_freehw: usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -860,12 +896,12 @@ static void ar9170_usb_disconnect(struct usb_interface *intf) ar9170_unregister(&aru->common); ar9170_usb_cancel_urbs(aru); - release_firmware(aru->init_values); - release_firmware(aru->firmware); - usb_put_dev(aru->udev); usb_set_intfdata(intf, NULL); ieee80211_free_hw(aru->common.hw); + + release_firmware(aru->init_values); + release_firmware(aru->firmware); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 6a3f4da7fb4..10b52262b23 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -429,8 +429,8 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; AR5K_EEPROM_READ(o++, val); - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + ee->ee_i_cal[mode] = (val >> 5) & 0x3f; + ee->ee_q_cal[mode] = val & 0x1f; if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { AR5K_EEPROM_READ(o++, val); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 72474c0ccaf..eff3323efb4 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1386,38 +1386,39 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, goto done; /* Calibration has finished, get the results and re-run */ + + /* work around empty results which can apparently happen on 5212 */ for (i = 0; i <= 10; i++) { iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "iq_corr:%x i_pwr:%x q_pwr:%x", iq_corr, i_pwr, q_pwr); + if (i_pwr && q_pwr) + break; } i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; q_coffd = q_pwr >> 7; - /* No correction */ - if (i_coffd == 0 || q_coffd == 0) + /* protect against divide by 0 and loss of sign bits */ + if (i_coffd == 0 || q_coffd < 2) goto done; - i_coff = ((-iq_corr) / i_coffd); - - /* Boundary check */ - if (i_coff > 31) - i_coff = 31; - if (i_coff < -32) - i_coff = -32; + i_coff = (-iq_corr) / i_coffd; + i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ - q_coff = (((s32)i_pwr / q_coffd) - 128); + q_coff = (i_pwr / q_coffd) - 128; + q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ - /* Boundary check */ - if (q_coff > 15) - q_coff = 15; - if (q_coff < -16) - q_coff = -16; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "new I:%d Q:%d (i_coffd:%x q_coffd:%x)", + i_coff, q_coff, i_coffd, q_coffd); - /* Commit new I/Q value */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | - ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); + /* Commit new I/Q values (set enable bit last to match HAL sources) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE); /* Re-enable calibration -if we don't we'll commit * the same values again and again */ @@ -1873,7 +1874,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) break; case AR5K_ANTMODE_FIXED_A: def_ant = 1; - tx_ant = 0; + tx_ant = 1; use_def_for_tx = true; update_def_on_tx = false; use_def_for_rts = true; @@ -1882,7 +1883,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) break; case AR5K_ANTMODE_FIXED_B: def_ant = 2; - tx_ant = 0; + tx_ant = 2; use_def_for_tx = true; update_def_on_tx = false; use_def_for_rts = true; diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 4cb9c5df9f4..1464f89b249 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -2187,6 +2187,7 @@ */ #define AR5K_PHY_IQ 0x9920 /* Register Address */ #define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ +#define AR5K_PHY_IQ_CORR_Q_Q_COFF_S 0 #define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ #define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 #define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index a35a7db0fc4..cbf28e37984 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -851,12 +851,15 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, AR5K_INIT_CYCRSSI_THR1); - /* I/Q correction - * TODO: Per channel i/q infos ? */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CORR_ENABLE | - (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | - ee->ee_q_cal[ee_mode]); + /* I/Q correction (set enable bit last to match HAL sources) */ + /* TODO: Per channel i/q infos ? */ + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, + ee->ee_i_cal[ee_mode]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, + ee->ee_q_cal[ee_mode]); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE); + } /* Heavy clipping -disable for now */ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1) @@ -1379,11 +1382,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_set_sleep_clock(ah, true); /* - * Disable beacons and reset the register + * Disable beacons and reset the TSF */ - AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | - AR5K_BEACON_RESET_TSF); - + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); + ath5k_hw_reset_tsf(ah); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ac34a055c71..0e79e58cf4c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1323,7 +1323,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, - u32 changed) + u32 changed, enum nl80211_channel_type oper_chan_type) { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; @@ -1340,8 +1340,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) return; - if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || - sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) + if (oper_chan_type == NL80211_CHAN_HT40MINUS || + oper_chan_type == NL80211_CHAN_HT40PLUS) oper_cw40 = true; oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 47294f90bbe..b2c8207f7bc 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2258,7 +2258,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) if (ATH_TXQ_SETUP(sc, i)) { txq = &sc->tx.txq[i]; - spin_lock(&txq->axq_lock); + spin_lock_bh(&txq->axq_lock); list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { @@ -2279,7 +2279,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } } - spin_unlock(&txq->axq_lock); + spin_unlock_bh(&txq->axq_lock); } } } diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 63c2a7ade5f..5c7aa1b1eb5 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -3177,14 +3177,27 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) int total_nr = 0; int i; struct pci_pool *pool; - u32 *virts[CB_NUMBER_OF_ELEMENTS_SMALL]; - dma_addr_t phys[CB_NUMBER_OF_ELEMENTS_SMALL]; + void **virts; + dma_addr_t *phys; IPW_DEBUG_TRACE("<< : \n"); + virts = kmalloc(sizeof(void *) * CB_NUMBER_OF_ELEMENTS_SMALL, + GFP_KERNEL); + if (!virts) + return -ENOMEM; + + phys = kmalloc(sizeof(dma_addr_t) * CB_NUMBER_OF_ELEMENTS_SMALL, + GFP_KERNEL); + if (!phys) { + kfree(virts); + return -ENOMEM; + } pool = pci_pool_create("ipw2200", priv->pci_dev, CB_MAX_LENGTH, 0, 0); if (!pool) { IPW_ERROR("pci_pool_create failed\n"); + kfree(phys); + kfree(virts); return -ENOMEM; } @@ -3254,6 +3267,8 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) pci_pool_free(pool, virts[i], phys[i]); pci_pool_destroy(pool); + kfree(phys); + kfree(virts); return ret; } diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index bf45391172f..a6d5e42647e 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -797,7 +797,7 @@ struct libipw_device { /* Probe / Beacon management */ struct list_head network_free_list; struct list_head network_list; - struct libipw_network *networks; + struct libipw_network *networks[MAX_NETWORK_COUNT]; int scans; int scan_age; diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 1ae0b2b02c3..2fa55867bd8 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -67,16 +67,17 @@ void *libipw_wiphy_privid = &libipw_wiphy_privid; static int libipw_networks_allocate(struct libipw_device *ieee) { - if (ieee->networks) - return 0; - - ieee->networks = - kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network), - GFP_KERNEL); - if (!ieee->networks) { - printk(KERN_WARNING "%s: Out of memory allocating beacons\n", - ieee->dev->name); - return -ENOMEM; + int i, j; + + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + ieee->networks[i] = kzalloc(sizeof(struct libipw_network), + GFP_KERNEL); + if (!ieee->networks[i]) { + LIBIPW_ERROR("Out of memory allocating beacons\n"); + for (j = 0; j < i; j++) + kfree(ieee->networks[j]); + return -ENOMEM; + } } return 0; @@ -97,15 +98,11 @@ static inline void libipw_networks_free(struct libipw_device *ieee) { int i; - if (!ieee->networks) - return; - - for (i = 0; i < MAX_NETWORK_COUNT; i++) - if (ieee->networks[i].ibss_dfs) - kfree(ieee->networks[i].ibss_dfs); - - kfree(ieee->networks); - ieee->networks = NULL; + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + if (ieee->networks[i]->ibss_dfs) + kfree(ieee->networks[i]->ibss_dfs); + kfree(ieee->networks[i]); + } } void libipw_networks_age(struct libipw_device *ieee, @@ -130,7 +127,7 @@ static void libipw_networks_initialize(struct libipw_device *ieee) INIT_LIST_HEAD(&ieee->network_free_list); INIT_LIST_HEAD(&ieee->network_list); for (i = 0; i < MAX_NETWORK_COUNT; i++) - list_add_tail(&ieee->networks[i].list, + list_add_tail(&ieee->networks[i]->list, &ieee->network_free_list); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 303cc8193ad..e0678d92105 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -184,7 +184,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp) { int idx; - for (idx = 0; idx < IWL_RATE_COUNT; idx++) + for (idx = 0; idx < IWL_RATE_COUNT_3945; idx++) if (iwl3945_rates[idx].plcp == plcp) return idx; return -1; @@ -805,7 +805,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, int sta_id, int tx_id) { u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; - u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT_3945); u16 rate_mask; int rate; u8 rts_retry_limit; @@ -2146,7 +2146,7 @@ static void iwl3945_hw_reg_init_channel_groups(struct iwl_priv *priv) /* fill in channel group's nominal powers for each rate */ for (rate_index = 0; - rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) { + rate_index < IWL_RATE_COUNT_3945; rate_index++, clip_pwrs++) { switch (rate_index) { case IWL_RATE_36M_INDEX_TABLE: if (i == 0) /* B/G */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6aeb82b6992..818367b57ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1463,59 +1463,66 @@ static void iwl_nic_start(struct iwl_priv *priv) } +static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); +static int iwl_mac_setup_register(struct iwl_priv *priv); + +static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) +{ + const char *name_pre = priv->cfg->fw_name_pre; + + if (first) + priv->fw_index = priv->cfg->ucode_api_max; + else + priv->fw_index--; + + if (priv->fw_index < priv->cfg->ucode_api_min) { + IWL_ERR(priv, "no suitable firmware found!\n"); + return -ENOENT; + } + + sprintf(priv->firmware_name, "%s%d%s", + name_pre, priv->fw_index, ".ucode"); + + IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n", + priv->firmware_name); + + return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, + &priv->pci_dev->dev, GFP_KERNEL, priv, + iwl_ucode_callback); +} + /** - * iwl_read_ucode - Read uCode images from disk file. + * iwl_ucode_callback - callback when firmware was loaded * - * Copy into buffers for card to fetch via bus-mastering + * If loaded successfully, copies the firmware into buffers + * for the card to fetch (via DMA). */ -static int iwl_read_ucode(struct iwl_priv *priv) +static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { + struct iwl_priv *priv = context; struct iwl_ucode_header *ucode; - int ret = -EINVAL, index; - const struct firmware *ucode_raw; - const char *name_pre = priv->cfg->fw_name_pre; const unsigned int api_max = priv->cfg->ucode_api_max; const unsigned int api_min = priv->cfg->ucode_api_min; - char buf[25]; u8 *src; size_t len; u32 api_ver, build; u32 inst_size, data_size, init_size, init_data_size, boot_size; + int err; u16 eeprom_ver; - /* Ask kernel firmware_class module to get the boot firmware off disk. - * request_firmware() is synchronous, file is in memory on return. */ - for (index = api_max; index >= api_min; index--) { - sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); - ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERR(priv, "%s firmware file req failed: %d\n", - buf, ret); - if (ret == -ENOENT) - continue; - else - goto error; - } else { - if (index < api_max) - IWL_ERR(priv, "Loaded firmware %s, " - "which is deprecated. " - "Please use API v%u instead.\n", - buf, api_max); - - IWL_DEBUG_INFO(priv, "Got firmware '%s' file (%zd bytes) from disk\n", - buf, ucode_raw->size); - break; - } + if (!ucode_raw) { + IWL_ERR(priv, "request for firmware file '%s' failed.\n", + priv->firmware_name); + goto try_again; } - if (ret < 0) - goto error; + IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", + priv->firmware_name, ucode_raw->size); /* Make sure that we got at least the v1 header! */ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { IWL_ERR(priv, "File size way too small!\n"); - ret = -EINVAL; - goto err_release; + goto try_again; } /* Data from ucode file: header followed by uCode images */ @@ -1540,10 +1547,9 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_ERR(priv, "Driver unable to support your firmware API. " "Driver supports v%u, firmware is v%u.\n", api_max, api_ver); - priv->ucode_ver = 0; - ret = -EINVAL; - goto err_release; + goto try_again; } + if (api_ver != api_max) IWL_ERR(priv, "Firmware has old API version. Expected v%u, " "got v%u. New firmware can be obtained " @@ -1585,6 +1591,12 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n", boot_size); + /* + * For any of the failures below (before allocating pci memory) + * we will try to load a version with a smaller API -- maybe the + * user just got a corrupted version of the latest API. + */ + /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) + @@ -1594,41 +1606,35 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "uCode file size %d does not match expected size\n", (int)ucode_raw->size); - ret = -EINVAL; - goto err_release; + goto try_again; } /* Verify that uCode images will fit in card's SRAM */ if (inst_size > priv->hw_params.max_inst_size) { IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n", inst_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (data_size > priv->hw_params.max_data_size) { IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n", data_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (init_size > priv->hw_params.max_inst_size) { IWL_INFO(priv, "uCode init instr len %d too large to fit in\n", init_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (init_data_size > priv->hw_params.max_data_size) { IWL_INFO(priv, "uCode init data len %d too large to fit in\n", init_data_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (boot_size > priv->hw_params.max_bsm_size) { IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n", boot_size); - ret = -EINVAL; - goto err_release; + goto try_again; } /* Allocate ucode buffers for card's bus-master loading ... */ @@ -1712,20 +1718,36 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); memcpy(priv->ucode_boot.v_addr, src, len); + /************************************************** + * This is still part of probe() in a sense... + * + * 9. Setup and register with mac80211 and debugfs + **************************************************/ + err = iwl_mac_setup_register(priv); + if (err) + goto out_unbind; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); - return 0; + return; + + try_again: + /* try next, if any */ + if (iwl_request_firmware(priv, false)) + goto out_unbind; + release_firmware(ucode_raw); + return; err_pci_alloc: IWL_ERR(priv, "failed to allocate pci memory\n"); - ret = -ENOMEM; iwl_dealloc_ucode_pci(priv); - - err_release: + out_unbind: + device_release_driver(&priv->pci_dev->dev); release_firmware(ucode_raw); - - error: - return ret; } static const char *desc_lookup_text[] = { @@ -2631,7 +2653,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) */ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX + 1; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; @@ -2667,21 +2689,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw) /* we should be verifying the device is ready to be opened */ mutex_lock(&priv->mutex); - - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - - if (!priv->ucode_code.len) { - ret = iwl_read_ucode(priv); - if (ret) { - IWL_ERR(priv, "Could not read microcode: %d\n", ret); - mutex_unlock(&priv->mutex); - return ret; - } - } - ret = __iwl_up(priv); - mutex_unlock(&priv->mutex); if (ret) @@ -3654,17 +3662,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_power_initialize(priv); iwl_tt_initialize(priv); - /************************************************** - * 9. Setup and register with mac80211 and debugfs - **************************************************/ - err = iwl_mac_setup_register(priv); + err = iwl_request_firmware(priv, true); if (err) goto out_remove_sysfs; - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - return 0; out_remove_sysfs: diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ab891b95804..6054c5fba0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1132,6 +1132,7 @@ struct iwl_priv { u8 rev_id; /* uCode images, save to reload in case of failure */ + int fw_index; /* firmware we're trying to load */ u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ @@ -1142,6 +1143,7 @@ struct iwl_priv { struct fw_desc ucode_boot; /* bootstrap inst */ enum ucode_type ucode_type; u8 ucode_write_complete; /* the image write is complete */ + char firmware_name[25]; struct iwl_rxon_time_cmd rxon_timing; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index dd9ff2ed645..bd2f7c42056 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -638,20 +638,9 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, if (left < 0) return 0; *pos++ = WLAN_EID_SSID; - if (!priv->is_internal_short_scan && - priv->scan_request->n_ssids) { - struct cfg80211_ssid *ssid = - priv->scan_request->ssids; - - /* Broadcast if ssid_len is 0 */ - *pos++ = ssid->ssid_len; - memcpy(pos, ssid->ssid, ssid->ssid_len); - pos += ssid->ssid_len; - len += 2 + ssid->ssid_len; - } else { - *pos++ = 0; - len += 2; - } + *pos++ = 0; + + len += 2; if (WARN_ON(left < ie_len)) return len; @@ -780,26 +769,20 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->is_internal_short_scan) { IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); } else if (priv->scan_request->n_ssids) { + int i, p = 0; IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - /* - * The first SSID to scan is stuffed into the probe request - * template and the remaining ones are handled through the - * direct_scan array. - */ - if (priv->scan_request->n_ssids > 1) { - int i, p = 0; - for (i = 1; i < priv->scan_request->n_ssids; i++) { - if (!priv->scan_request->ssids[i].ssid_len) - continue; - scan->direct_scan[p].id = WLAN_EID_SSID; - scan->direct_scan[p].len = - priv->scan_request->ssids[i].ssid_len; - memcpy(scan->direct_scan[p].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - n_probes++; - p++; - } + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; } is_active = true; } else diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9f6d6bf06b8..2887047069f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1496,51 +1496,67 @@ static void set_multicast_list(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct dev_mc_list *mclist; - __le32 filter; - int ret, i, size; - char *buf; + __le32 filter, basefilter; + int ret; + char *mc_addrs = NULL; + int mc_count; - filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; + basefilter = filter = RNDIS_PACKET_TYPE_DIRECTED | + RNDIS_PACKET_TYPE_BROADCAST; - netif_addr_lock_bh(usbdev->net); if (usbdev->net->flags & IFF_PROMISC) { filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | RNDIS_PACKET_TYPE_ALL_LOCAL; - } else if (usbdev->net->flags & IFF_ALLMULTI || - netdev_mc_count(usbdev->net) > priv->multicast_size) { + } else if (usbdev->net->flags & IFF_ALLMULTI) { + filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; + } + + if (filter != basefilter) + goto set_filter; + + /* + * mc_list should be accessed holding the lock, so copy addresses to + * local buffer first. + */ + netif_addr_lock_bh(usbdev->net); + mc_count = netdev_mc_count(usbdev->net); + if (mc_count > priv->multicast_size) { filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; - } else if (!netdev_mc_empty(usbdev->net)) { - size = min(priv->multicast_size, netdev_mc_count(usbdev->net)); - buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); - if (!buf) { + } else if (mc_count) { + int i = 0; + + mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC); + if (!mc_addrs) { netdev_warn(usbdev->net, "couldn't alloc %d bytes of memory\n", - size * ETH_ALEN); + mc_count * ETH_ALEN); netif_addr_unlock_bh(usbdev->net); return; } - i = 0; - netdev_for_each_mc_addr(mclist, usbdev->net) { - if (i == size) - break; - memcpy(buf + i++ * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); - } + netdev_for_each_mc_addr(mclist, usbdev->net) + memcpy(mc_addrs + i++ * ETH_ALEN, + mclist->dmi_addr, ETH_ALEN); + } + netif_addr_unlock_bh(usbdev->net); - ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf, - i * ETH_ALEN); - if (ret == 0 && i > 0) + if (filter != basefilter) + goto set_filter; + + if (mc_count) { + ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, mc_addrs, + mc_count * ETH_ALEN); + kfree(mc_addrs); + if (ret == 0) filter |= RNDIS_PACKET_TYPE_MULTICAST; else filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", - i, priv->multicast_size, ret); - - kfree(buf); + mc_count, priv->multicast_size, ret); } - netif_addr_unlock_bh(usbdev->net); +set_filter: ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter)); if (ret < 0) { diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index aca8c124f43..91cce2d0f6d 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1225,7 +1225,7 @@ MODULE_LICENSE("GPL"); #ifdef CONFIG_RT2800PCI_SOC static int rt2800soc_probe(struct platform_device *pdev) { - return rt2x00soc_probe(pdev, rt2800pci_ops); + return rt2x00soc_probe(pdev, &rt2800pci_ops); } static struct platform_driver rt2800soc_driver = { diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 4efdc96010f..111c0ff5c6c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -112,6 +112,7 @@ exit_free_device: return retval; } +EXPORT_SYMBOL_GPL(rt2x00soc_probe); int rt2x00soc_remove(struct platform_device *pdev) { diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h index 4739edfe2f0..474cbfc1efc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -26,8 +26,6 @@ #ifndef RT2X00SOC_H #define RT2X00SOC_H -#define KSEG1ADDR(__ptr) __ptr - /* * SoC driver handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e77aec8d0a8..290d70bc5d2 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2352,6 +2352,8 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, + /* CEIVA */ + { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) }, /* CNet */ { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a22a1920312..00e09e26c82 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -350,7 +350,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, first_idx = info->status.rates[0].idx; ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates)); retries = &zd_retry_rates[first_idx]; - ZD_ASSERT(0<=retry && retry<=retries->count); + ZD_ASSERT(1 <= retry && retry <= retries->count); info->status.rates[0].idx = retries->rate[0]; info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1); @@ -360,7 +360,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2); } for (; i<IEEE80211_TX_MAX_RATES && i<retry; i++) { - info->status.rates[i].idx = retries->rate[retry-1]; + info->status.rates[i].idx = retries->rate[retry - 1]; info->status.rates[i].count = 1; // (success ? 1:2); } if (i<IEEE80211_TX_MAX_RATES) @@ -424,12 +424,10 @@ void zd_mac_tx_failed(struct urb *urb) first_idx = info->status.rates[0].idx; ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates)); retries = &zd_retry_rates[first_idx]; - if (retry < 0 || retry > retries->count) { + if (retry <= 0 || retry > retries->count) continue; - } - ZD_ASSERT(0<=retry && retry<=retries->count); - final_idx = retries->rate[retry-1]; + final_idx = retries->rate[retry - 1]; final_rate = zd_rates[final_idx].hw_value; if (final_rate != tx_status->rate) { |