diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
21 files changed, 205 insertions, 73 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 47909f94271..902c4d4293e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -27,6 +27,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <linux/wireless.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e0678d92105..0728054a22d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -27,6 +27,7 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1bd2cd83602..8972166386c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2015,7 +2015,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,  			IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "  					   "%d index %d\n", scd_ssn , index);  			freed = iwl_tx_queue_reclaim(priv, txq_id, index); -			iwl_free_tfds_in_queue(priv, sta_id, tid, freed); +			if (qc) +				iwl_free_tfds_in_queue(priv, sta_id, +						       tid, freed);  			if (priv->mac80211_registered &&  			    (iwl_queue_space(&txq->q) > txq->q.low_mark) && @@ -2042,13 +2044,14 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,  		freed = iwl_tx_queue_reclaim(priv, txq_id, index);  		if (qc && likely(sta_id != IWL_INVALID_STATION)) -			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; +			iwl_free_tfds_in_queue(priv, sta_id, tid, freed); +		else if (sta_id == IWL_INVALID_STATION) +			IWL_DEBUG_TX_REPLY(priv, "Station not known\n");  		if (priv->mac80211_registered &&  		    (iwl_queue_space(&txq->q) > txq->q.low_mark))  			iwl_wake_queue(priv, txq_id);  	} -  	if (qc && likely(sta_id != IWL_INVALID_STATION))  		iwl_txq_check_empty(priv, sta_id, tid, txq_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c4844adff92..92b3e64fc14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -259,7 +259,7 @@ static struct iwl_lib_ops iwl6000_lib = {  			EEPROM_5000_REG_BAND_3_CHANNELS,  			EEPROM_5000_REG_BAND_4_CHANNELS,  			EEPROM_5000_REG_BAND_5_CHANNELS, -			EEPROM_5000_REG_BAND_24_HT40_CHANNELS, +			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,  			EEPROM_5000_REG_BAND_52_HT40_CHANNELS  		},  		.verify_signature  = iwlcore_eeprom_verify_signature, @@ -323,7 +323,7 @@ static struct iwl_lib_ops iwl6050_lib = {  			EEPROM_5000_REG_BAND_3_CHANNELS,  			EEPROM_5000_REG_BAND_4_CHANNELS,  			EEPROM_5000_REG_BAND_5_CHANNELS, -			EEPROM_5000_REG_BAND_24_HT40_CHANNELS, +			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,  			EEPROM_5000_REG_BAND_52_HT40_CHANNELS  		},  		.verify_signature  = iwlcore_eeprom_verify_signature, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8bf7c20b9d3..1460116d329 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -26,6 +26,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <linux/wireless.h>  #include <net/mac80211.h> @@ -345,6 +346,17 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)  	       !!(rate_n_flags & RATE_MCS_ANT_C_MSK);  } +/* + * Static function to get the expected throughput from an iwl_scale_tbl_info + * that wraps a NULL pointer check + */ +static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) +{ +	if (tbl->expected_tpt) +		return tbl->expected_tpt[rs_index]; +	return 0; +} +  /**   * rs_collect_tx_data - Update the success/failure sliding window   * @@ -352,19 +364,21 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)   * at this rate.  window->data contains the bitmask of successful   * packets.   */ -static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, -			      int scale_index, s32 tpt, int attempts, -			      int successes) +static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, +			      int scale_index, int attempts, int successes)  {  	struct iwl_rate_scale_data *window = NULL;  	static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); -	s32 fail_count; +	s32 fail_count, tpt;  	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)  		return -EINVAL;  	/* Select window for current tx bit rate */ -	window = &(windows[scale_index]); +	window = &(tbl->win[scale_index]); + +	/* Get expected throughput */ +	tpt = get_expected_tpt(tbl, scale_index);  	/*  	 * Keep track of only the latest 62 tx frame attempts in this rate's @@ -738,16 +752,6 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,  	return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&  		(a->is_SGI == b->is_SGI);  } -/* - * Static function to get the expected throughput from an iwl_scale_tbl_info - * that wraps a NULL pointer check - */ -static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) -{ -	if (tbl->expected_tpt) -		return tbl->expected_tpt[rs_index]; -	return 0; -}  /*   * mac80211 sends us Tx status @@ -764,12 +768,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct iwl_priv *priv = (struct iwl_priv *)priv_r;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -	struct iwl_rate_scale_data *window = NULL;  	enum mac80211_rate_control_flags mac_flags;  	u32 tx_rate;  	struct iwl_scale_tbl_info tbl_type; -	struct iwl_scale_tbl_info *curr_tbl, *other_tbl; -	s32 tpt = 0; +	struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;  	IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); @@ -852,7 +854,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  		IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");  		return;  	} -	window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);  	/*  	 * Updating the frame history depends on whether packets were @@ -865,8 +866,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  		tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);  		rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,  				&rs_index); -		tpt = get_expected_tpt(curr_tbl, rs_index); -		rs_collect_tx_data(window, rs_index, tpt, +		rs_collect_tx_data(curr_tbl, rs_index,  				   info->status.ampdu_ack_len,  				   info->status.ampdu_ack_map); @@ -896,19 +896,13 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  			 * table as active/search.  			 */  			if (table_type_matches(&tbl_type, curr_tbl)) -				tpt = get_expected_tpt(curr_tbl, rs_index); +				tmp_tbl = curr_tbl;  			else if (table_type_matches(&tbl_type, other_tbl)) -				tpt = get_expected_tpt(other_tbl, rs_index); +				tmp_tbl = other_tbl;  			else  				continue; - -			/* Constants mean 1 transmission, 0 successes */ -			if (i < retries) -				rs_collect_tx_data(window, rs_index, tpt, 1, -						0); -			else -				rs_collect_tx_data(window, rs_index, tpt, 1, -						legacy_success); +			rs_collect_tx_data(tmp_tbl, rs_index, 1, +					   i < retries ? 0 : legacy_success);  		}  		/* Update success/fail counts if not searching for new mode */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 818367b57ba..bdff56583e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -31,6 +31,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h>  #include <linux/sched.h> @@ -1258,7 +1259,15 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)  	/* Ack/clear/reset pending uCode interrupts.  	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,  	 */ -	iwl_write32(priv, CSR_INT, priv->inta); +	/* There is a hardware bug in the interrupt mask function that some +	 * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if +	 * they are disabled in the CSR_INT_MASK register. Furthermore the +	 * ICT interrupt handling mechanism has another bug that might cause +	 * these unmasked interrupts fail to be detected. We workaround the +	 * hardware bugs here by ACKing all the possible interrupts so that +	 * interrupt coalescing can still be achieved. +	 */ +	iwl_write32(priv, CSR_INT, priv->inta | ~priv->inta_mask);  	inta = priv->inta; @@ -2644,7 +2653,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)  		BIT(NL80211_IFTYPE_STATION) |  		BIT(NL80211_IFTYPE_ADHOC); -	hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | +	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |  			    WIPHY_FLAG_DISABLE_BEACON_HINTS;  	/* @@ -3322,6 +3331,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)  	cancel_delayed_work_sync(&priv->init_alive_start);  	cancel_delayed_work(&priv->scan_check); +	cancel_work_sync(&priv->start_internal_scan);  	cancel_delayed_work(&priv->alive_start);  	cancel_work_sync(&priv->beacon_update);  	del_timer_sync(&priv->statistics_periodic); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 845831ac053..8b516c5ff0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -60,6 +60,7 @@   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   *****************************************************************************/ +#include <linux/slab.h>  #include <net/mac80211.h>  #include "iwl-dev.h" @@ -807,6 +808,18 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,  		}  	} +	/* +	 * The above algorithm sometimes fails when the ucode +	 * reports 0 for all chains. It's not clear why that +	 * happens to start with, but it is then causing trouble +	 * because this can make us enable more chains than the +	 * hardware really has. +	 * +	 * To be safe, simply mask out any chains that we know +	 * are not on the device. +	 */ +	active_chains &= priv->hw_params.valid_rx_ant; +  	num_tx_chains = 0;  	for (i = 0; i < NUM_RX_CHAINS; i++) {  		/* loops on all the bits of diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 112149e9b31..049b652bcb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -30,6 +30,7 @@  #include <linux/module.h>  #include <linux/etherdevice.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include "iwl-eeprom.h" @@ -307,10 +308,13 @@ int iwl_hw_nic_init(struct iwl_priv *priv)  	spin_unlock_irqrestore(&priv->lock, flags); -	/* Allocate and init all Tx and Command queues */ -	ret = iwl_txq_ctx_reset(priv); -	if (ret) -		return ret; +	/* Allocate or reset and init all Tx and Command queues */ +	if (!priv->txq) { +		ret = iwl_txq_ctx_alloc(priv); +		if (ret) +			return ret; +	} else +		iwl_txq_ctx_reset(priv);  	set_bit(STATUS_INIT, &priv->status); @@ -3354,7 +3358,6 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)  	 */  	IWL_DEBUG_INFO(priv, "perform radio reset.\n");  	iwl_internal_short_hw_scan(priv); -	return;  } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4ef7739f9e8..36940a9ec6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -442,7 +442,8 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);  /*****************************************************  * TX  ******************************************************/ -int iwl_txq_ctx_reset(struct iwl_priv *priv); +int iwl_txq_ctx_alloc(struct iwl_priv *priv); +void iwl_txq_ctx_reset(struct iwl_priv *priv);  void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);  int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,  				 struct iwl_tx_queue *txq, @@ -456,6 +457,8 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,  void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);  int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,  		      int slots_num, u32 txq_id); +void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, +			int slots_num, u32 txq_id);  void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);  int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);  int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); @@ -503,7 +506,7 @@ void iwl_init_scan_params(struct iwl_priv *priv);  int iwl_scan_cancel(struct iwl_priv *priv);  int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);  int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); -int iwl_internal_short_hw_scan(struct iwl_priv *priv); +void iwl_internal_short_hw_scan(struct iwl_priv *priv);  int iwl_force_reset(struct iwl_priv *priv, int mode);  u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,  		       const u8 *ie, int ie_len, int left); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7bf44f14679..b6e1b0ebe23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -26,6 +26,7 @@   * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497   *****************************************************************************/ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/debugfs.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6054c5fba0c..ef1720a852e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1296,6 +1296,7 @@ struct iwl_priv {  	struct work_struct tt_work;  	struct work_struct ct_enter;  	struct work_struct ct_exit; +	struct work_struct start_internal_scan;  	struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 36580d8d8b8..2ffc2edbf4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -28,6 +28,8 @@  /* sparse doesn't like tracepoint macros */  #ifndef __CHECKER__ +#include "iwl-dev.h" +  #define CREATE_TRACE_POINTS  #include "iwl-devtrace.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index ff4d012ce26..ae7319bb3a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -28,7 +28,6 @@  #define __IWLWIFI_DEVICE_TRACE  #include <linux/tracepoint.h> -#include "iwl-dev.h"  #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)  #undef TRACE_EVENT diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index fd37152abae..fb5bb487f3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -63,6 +63,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 4e1ba824dc5..8171c701e4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -203,6 +203,10 @@ struct iwl_eeprom_enhanced_txpwr {  #define EEPROM_5000_REG_BAND_52_HT40_CHANNELS  ((0x92)\  		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */ +/* 6000 regulatory - indirect access */ +#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS  ((0x80)\ +		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */ +  /* 6000 and up regulatory tx power - indirect access */  /* max. elements per section */  #define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS	(8) diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index c719baf2585..16eb3ced9b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -31,6 +31,7 @@  #include <linux/io.h> +#include "iwl-dev.h"  #include "iwl-debug.h"  #include "iwl-devtrace.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 1a1a9f081cc..548dac2f6a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -29,6 +29,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index df257bc15f4..e5eb339107d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -28,6 +28,7 @@   *****************************************************************************/  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include <asm/unaligned.h>  #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index bd2f7c42056..12e455a4b90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -25,6 +25,7 @@   *  Intel Linux Wireless <ilw@linux.intel.com>   * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497   *****************************************************************************/ +#include <linux/slab.h>  #include <linux/types.h>  #include <linux/etherdevice.h>  #include <net/mac80211.h> @@ -469,6 +470,8 @@ EXPORT_SYMBOL(iwl_init_scan_params);  static int iwl_scan_initiate(struct iwl_priv *priv)  { +	WARN_ON(!mutex_is_locked(&priv->mutex)); +  	IWL_DEBUG_INFO(priv, "Starting scan...\n");  	set_bit(STATUS_SCANNING, &priv->status);  	priv->is_internal_short_scan = false; @@ -546,24 +549,31 @@ EXPORT_SYMBOL(iwl_mac_hw_scan);   * internal short scan, this function should only been called while associated.   * It will reset and tune the radio to prevent possible RF related problem   */ -int iwl_internal_short_hw_scan(struct iwl_priv *priv) +void iwl_internal_short_hw_scan(struct iwl_priv *priv)  { -	int ret = 0; +	queue_work(priv->workqueue, &priv->start_internal_scan); +} + +static void iwl_bg_start_internal_scan(struct work_struct *work) +{ +	struct iwl_priv *priv = +		container_of(work, struct iwl_priv, start_internal_scan); + +	mutex_lock(&priv->mutex);  	if (!iwl_is_ready_rf(priv)) { -		ret = -EIO;  		IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); -		goto out; +		goto unlock;  	} +  	if (test_bit(STATUS_SCANNING, &priv->status)) {  		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); -		ret = -EAGAIN; -		goto out; +		goto unlock;  	} +  	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {  		IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); -		ret = -EAGAIN; -		goto out; +		goto unlock;  	}  	priv->scan_bands = 0; @@ -576,9 +586,8 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv)  	set_bit(STATUS_SCANNING, &priv->status);  	priv->is_internal_short_scan = true;  	queue_work(priv->workqueue, &priv->request_scan); - -out: -	return ret; + unlock: +	mutex_unlock(&priv->mutex);  }  EXPORT_SYMBOL(iwl_internal_short_hw_scan); @@ -964,6 +973,7 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv)  	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);  	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);  	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); +	INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);  	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);  }  EXPORT_SYMBOL(iwl_setup_scan_deferred_work); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1ed5206721e..8dd0c036d54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -29,6 +29,7 @@  #include <linux/etherdevice.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include "iwl-eeprom.h"  #include "iwl-dev.h" @@ -124,7 +125,7 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,  	if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)  		priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;  	else { -		IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n", +		IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",  			priv->stations[sta_id].tid[tid].tfds_in_queue,  			freed);  		priv->stations[sta_id].tid[tid].tfds_in_queue = 0; @@ -193,10 +194,34 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)  	struct iwl_queue *q = &txq->q;  	struct device *dev = &priv->pci_dev->dev;  	int i; +	bool huge = false;  	if (q->n_bd == 0)  		return; +	for (; q->read_ptr != q->write_ptr; +	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { +		/* we have no way to tell if it is a huge cmd ATM */ +		i = get_cmd_index(q, q->read_ptr, 0); + +		if (txq->meta[i].flags & CMD_SIZE_HUGE) { +			huge = true; +			continue; +		} + +		pci_unmap_single(priv->pci_dev, +				 pci_unmap_addr(&txq->meta[i], mapping), +				 pci_unmap_len(&txq->meta[i], len), +				 PCI_DMA_BIDIRECTIONAL); +	} +	if (huge) { +		i = q->n_window; +		pci_unmap_single(priv->pci_dev, +				 pci_unmap_addr(&txq->meta[i], mapping), +				 pci_unmap_len(&txq->meta[i], len), +				 PCI_DMA_BIDIRECTIONAL); +	} +  	/* De-alloc array of command/tx buffers */  	for (i = 0; i <= TFD_CMD_SLOTS; i++)  		kfree(txq->cmd[i]); @@ -409,6 +434,26 @@ out_free_arrays:  }  EXPORT_SYMBOL(iwl_tx_queue_init); +void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, +			int slots_num, u32 txq_id) +{ +	int actual_slots = slots_num; + +	if (txq_id == IWL_CMD_QUEUE_NUM) +		actual_slots++; + +	memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots); + +	txq->need_update = 0; + +	/* Initialize queue's high/low-water marks, and head/tail indexes */ +	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + +	/* Tell device where to find queue */ +	priv->cfg->ops->lib->txq_init(priv, txq); +} +EXPORT_SYMBOL(iwl_tx_queue_reset); +  /**   * iwl_hw_txq_ctx_free - Free TXQ Context   * @@ -420,8 +465,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)  	/* Tx queues */  	if (priv->txq) { -		for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; -		     txq_id++) +		for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)  			if (txq_id == IWL_CMD_QUEUE_NUM)  				iwl_cmd_queue_free(priv);  			else @@ -437,15 +481,15 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)  EXPORT_SYMBOL(iwl_hw_txq_ctx_free);  /** - * iwl_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialize them again + * iwl_txq_ctx_alloc - allocate TX queue context + * Allocate all Tx DMA structures and initialize them   *   * @param priv   * @return error code   */ -int iwl_txq_ctx_reset(struct iwl_priv *priv) +int iwl_txq_ctx_alloc(struct iwl_priv *priv)  { -	int ret = 0; +	int ret;  	int txq_id, slots_num;  	unsigned long flags; @@ -503,8 +547,31 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)  	return ret;  } +void iwl_txq_ctx_reset(struct iwl_priv *priv) +{ +	int txq_id, slots_num; +	unsigned long flags; + +	spin_lock_irqsave(&priv->lock, flags); + +	/* Turn off all Tx DMA fifos */ +	priv->cfg->ops->lib->txq_set_sched(priv, 0); + +	/* Tell NIC where to find the "keep warm" buffer */ +	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); + +	spin_unlock_irqrestore(&priv->lock, flags); + +	/* Alloc and init all Tx queues, including the command queue (#4) */ +	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { +		slots_num = txq_id == IWL_CMD_QUEUE_NUM ? +			    TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; +		iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id); +	} +} +  /** - * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory + * iwl_txq_ctx_stop - Stop all Tx DMA channels   */  void iwl_txq_ctx_stop(struct iwl_priv *priv)  { @@ -524,9 +591,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)  				    1000);  	}  	spin_unlock_irqrestore(&priv->lock, flags); - -	/* Deallocate memory for all Tx queues */ -	iwl_hw_txq_ctx_free(priv);  }  EXPORT_SYMBOL(iwl_txq_ctx_stop); @@ -1049,6 +1113,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)  	spin_lock_irqsave(&priv->hcmd_lock, flags); +	/* If this is a huge cmd, mark the huge flag also on the meta.flags +	 * of the _original_ cmd. This is used for DMA mapping clean up. +	 */ +	if (cmd->flags & CMD_SIZE_HUGE) { +		idx = get_cmd_index(q, q->write_ptr, 0); +		txq->meta[idx].flags = CMD_SIZE_HUGE; +	} +  	idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);  	out_cmd = txq->cmd[idx];  	out_meta = &txq->meta[idx]; @@ -1226,6 +1298,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)  	bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);  	struct iwl_device_cmd *cmd;  	struct iwl_cmd_meta *meta; +	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];  	/* If a Tx command is being handled and it isn't in the actual  	 * command queue then there a command routing bug has been introduced @@ -1239,9 +1312,17 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)  		return;  	} -	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); -	cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; -	meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; +	/* If this is a huge cmd, clear the huge flag on the meta.flags +	 * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap +	 * the DMA buffer for the scan (huge) command. +	 */ +	if (huge) { +		cmd_index = get_cmd_index(&txq->q, index, 0); +		txq->meta[cmd_index].flags = 0; +	} +	cmd_index = get_cmd_index(&txq->q, index, huge); +	cmd = txq->cmd[cmd_index]; +	meta = &txq->meta[cmd_index];  	pci_unmap_single(priv->pci_dev,  			 pci_unmap_addr(meta, mapping), @@ -1263,6 +1344,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)  			       get_cmd_string(cmd->hdr.cmd));  		wake_up_interruptible(&priv->wait_command_queue);  	} +	meta->flags = 0;  }  EXPORT_SYMBOL(iwl_tx_cmd_complete); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 54daa38ecba..b55e4f39a9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -31,6 +31,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h>  #include <linux/sched.h> @@ -1955,7 +1956,7 @@ static void iwl3945_init_hw_rates(struct iwl_priv *priv,  {  	int i; -	for (i = 0; i < IWL_RATE_COUNT; i++) { +	for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {  		rates[i].bitrate = iwl3945_rates[i].ieee * 5;  		rates[i].hw_value = i; /* Rate scaling will work on indexes */  		rates[i].hw_value_short = i; @@ -3921,7 +3922,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)  		BIT(NL80211_IFTYPE_STATION) |  		BIT(NL80211_IFTYPE_ADHOC); -	hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | +	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |  			    WIPHY_FLAG_DISABLE_BEACON_HINTS;  	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;  |