diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 434 | 
1 files changed, 223 insertions, 211 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d31661c1ce7..8f8c4b73f8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -33,6 +33,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/pci-aspm.h>  #include <linux/slab.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h> @@ -143,7 +144,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,  	key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);  	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); -	if (sta_id == priv->hw_params.bcast_sta_id) +	if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)  		key_flags |= STA_KEY_MULTICAST_MSK;  	keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; @@ -151,7 +152,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,  	key_flags &= ~STA_KEY_FLG_INVALID;  	spin_lock_irqsave(&priv->sta_lock, flags); -	priv->stations[sta_id].keyinfo.alg = keyconf->alg; +	priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;  	priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;  	memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,  	       keyconf->keylen); @@ -222,23 +223,25 @@ static int iwl3945_set_dynamic_key(struct iwl_priv *priv,  	keyconf->hw_key_idx = HW_KEY_DYNAMIC; -	switch (keyconf->alg) { -	case ALG_CCMP: +	switch (keyconf->cipher) { +	case WLAN_CIPHER_SUITE_CCMP:  		ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);  		break; -	case ALG_TKIP: +	case WLAN_CIPHER_SUITE_TKIP:  		ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);  		break; -	case ALG_WEP: +	case WLAN_CIPHER_SUITE_WEP40: +	case WLAN_CIPHER_SUITE_WEP104:  		ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);  		break;  	default: -		IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg); +		IWL_ERR(priv, "Unknown alg: %s alg=%x\n", __func__, +			keyconf->cipher);  		ret = -EINVAL;  	} -	IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n", -		      keyconf->alg, keyconf->keylen, keyconf->keyidx, +	IWL_DEBUG_WEP(priv, "Set dynamic key: alg=%x len=%d idx=%d sta=%d ret=%d\n", +		      keyconf->cipher, keyconf->keylen, keyconf->keyidx,  		      sta_id, ret);  	return ret; @@ -254,10 +257,11 @@ static int iwl3945_remove_static_key(struct iwl_priv *priv)  static int iwl3945_set_static_key(struct iwl_priv *priv,  				struct ieee80211_key_conf *key)  { -	if (key->alg == ALG_WEP) +	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || +	    key->cipher == WLAN_CIPHER_SUITE_WEP104)  		return -EOPNOTSUPP; -	IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg); +	IWL_ERR(priv, "Static key invalid: cipher %x\n", key->cipher);  	return -EINVAL;  } @@ -313,15 +317,15 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,  				int left)  { -	if (!iwl_is_associated(priv) || !priv->ibss_beacon) +	if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->beacon_skb)  		return 0; -	if (priv->ibss_beacon->len > left) +	if (priv->beacon_skb->len > left)  		return 0; -	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); +	memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); -	return priv->ibss_beacon->len; +	return priv->beacon_skb->len;  }  static int iwl3945_send_beacon_cmd(struct iwl_priv *priv) @@ -339,7 +343,8 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)  		return -ENOMEM;  	} -	rate = iwl_rate_get_lowest_plcp(priv); +	rate = iwl_rate_get_lowest_plcp(priv, +				&priv->contexts[IWL_RXON_CTX_BSS]);  	frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate); @@ -369,23 +374,25 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,  	struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;  	struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; -	switch (keyinfo->alg) { -	case ALG_CCMP: +	tx_cmd->sec_ctl = 0; + +	switch (keyinfo->cipher) { +	case WLAN_CIPHER_SUITE_CCMP:  		tx_cmd->sec_ctl = TX_CMD_SEC_CCM;  		memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);  		IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");  		break; -	case ALG_TKIP: +	case WLAN_CIPHER_SUITE_TKIP:  		break; -	case ALG_WEP: -		tx_cmd->sec_ctl = TX_CMD_SEC_WEP | +	case WLAN_CIPHER_SUITE_WEP104: +		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; +		/* fall through */ +	case WLAN_CIPHER_SUITE_WEP40: +		tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |  		    (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; -		if (keyinfo->keylen == 13) -			tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; -  		memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);  		IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption " @@ -393,7 +400,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,  		break;  	default: -		IWL_ERR(priv, "Unknown encode alg %d\n", keyinfo->alg); +		IWL_ERR(priv, "Unknown encode cipher %x\n", keyinfo->cipher);  		break;  	}  } @@ -506,7 +513,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)  	hdr_len = ieee80211_hdrlen(fc);  	/* Find index into station table for destination station */ -	sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta); +	sta_id = iwl_sta_id_or_broadcast( +			priv, &priv->contexts[IWL_RXON_CTX_BSS], +			info->control.sta);  	if (sta_id == IWL_INVALID_STATION) {  		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",  			       hdr->addr1); @@ -536,6 +545,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)  	/* Set up driver data for this TFD */  	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));  	txq->txb[q->write_ptr].skb = skb; +	txq->txb[q->write_ptr].ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	/* Init first empty entry in queue's array of Tx/cmd buffers */  	out_cmd = txq->cmd[idx]; @@ -677,11 +687,12 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,  	int rc;  	int spectrum_resp_status;  	int duration = le16_to_cpu(params->duration); +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; -	if (iwl_is_associated(priv)) +	if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))  		add_time = iwl_usecs_to_beacons(priv,  			le64_to_cpu(params->start_time) - priv->_3945.last_tsf, -			le16_to_cpu(priv->rxon_timing.beacon_interval)); +			le16_to_cpu(ctx->timing.beacon_interval));  	memset(&spectrum, 0, sizeof(spectrum)); @@ -692,18 +703,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,  	cmd.len = sizeof(spectrum);  	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); -	if (iwl_is_associated(priv)) +	if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))  		spectrum.start_time =  			iwl_add_beacon_time(priv,  				priv->_3945.last_beacon_time, add_time, -				le16_to_cpu(priv->rxon_timing.beacon_interval)); +				le16_to_cpu(ctx->timing.beacon_interval));  	else  		spectrum.start_time = 0;  	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);  	spectrum.channels[0].channel = params->channel;  	spectrum.channels[0].type = type; -	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) +	if (ctx->active.flags & RXON_FLG_BAND_24G_MSK)  		spectrum.flags |= RXON_FLG_BAND_24G_MSK |  		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; @@ -792,7 +803,8 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)  	struct sk_buff *beacon;  	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */ -	beacon = ieee80211_beacon_get(priv->hw, priv->vif); +	beacon = ieee80211_beacon_get(priv->hw, +			priv->contexts[IWL_RXON_CTX_BSS].vif);  	if (!beacon) {  		IWL_ERR(priv, "update beacon failed\n"); @@ -801,10 +813,10 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)  	mutex_lock(&priv->mutex);  	/* new beacon skb is allocated every time; dispose previous.*/ -	if (priv->ibss_beacon) -		dev_kfree_skb(priv->ibss_beacon); +	if (priv->beacon_skb) +		dev_kfree_skb(priv->beacon_skb); -	priv->ibss_beacon = beacon; +	priv->beacon_skb = beacon;  	mutex_unlock(&priv->mutex);  	iwl3945_send_beacon_cmd(priv); @@ -813,9 +825,9 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)  static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,  				struct iwl_rx_mem_buffer *rxb)  { -#ifdef CONFIG_IWLWIFI_DEBUG  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status); +#ifdef CONFIG_IWLWIFI_DEBUG  	u8 rate = beacon->beacon_notify_hdr.rate;  	IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d " @@ -827,6 +839,8 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,  		le32_to_cpu(beacon->low_tsf), rate);  #endif +	priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); +  	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&  	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))  		queue_work(priv->workqueue, &priv->beacon_update); @@ -1567,16 +1581,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,  	num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));  	next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); -	if (capacity > priv->cfg->max_event_log_size) { +	if (capacity > priv->cfg->base_params->max_event_log_size) {  		IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", -			capacity, priv->cfg->max_event_log_size); -		capacity = priv->cfg->max_event_log_size; +			capacity, priv->cfg->base_params->max_event_log_size); +		capacity = priv->cfg->base_params->max_event_log_size;  	} -	if (next_entry > priv->cfg->max_event_log_size) { +	if (next_entry > priv->cfg->base_params->max_event_log_size) {  		IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", -			next_entry, priv->cfg->max_event_log_size); -		next_entry = priv->cfg->max_event_log_size; +			next_entry, priv->cfg->base_params->max_event_log_size); +		next_entry = priv->cfg->base_params->max_event_log_size;  	}  	size = num_wraps ? capacity : next_entry; @@ -1716,7 +1730,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)  		IWL_ERR(priv, "Microcode SW error detected. "  			"Restarting 0x%X.\n", inta);  		priv->isr_stats.sw++; -		priv->isr_stats.sw_err = inta;  		iwl_irq_handle_error(priv);  		handled |= CSR_INT_BIT_SW_ERR;  	} @@ -2460,6 +2473,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)  {  	int thermal_spin = 0;  	u32 rfkill; +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); @@ -2505,7 +2519,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)  		/* Enable timer to monitor the driver queues */  		mod_timer(&priv->monitor_recover,  			jiffies + -			msecs_to_jiffies(priv->cfg->monitor_recover_period)); +			msecs_to_jiffies( +			  priv->cfg->base_params->monitor_recover_period));  	}  	if (iwl_is_rfkill(priv)) @@ -2517,22 +2532,22 @@ static void iwl3945_alive_start(struct iwl_priv *priv)  	iwl_power_update_mode(priv, true); -	if (iwl_is_associated(priv)) { +	if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {  		struct iwl3945_rxon_cmd *active_rxon = -				(struct iwl3945_rxon_cmd *)(&priv->active_rxon); +				(struct iwl3945_rxon_cmd *)(&ctx->active); -		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; +		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;  		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;  	} else {  		/* Initialize our rx_config data */ -		iwl_connection_init_rx_config(priv, NULL); +		iwl_connection_init_rx_config(priv, ctx);  	}  	/* Configure Bluetooth device coexistence support */  	priv->cfg->ops->hcmd->send_bt_config(priv);  	/* Configure the adapter for unassociated operation */ -	iwlcore_commit_rxon(priv); +	iwl3945_commit_rxon(priv, ctx);  	iwl3945_reg_txpower_periodic(priv); @@ -2553,19 +2568,22 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv);  static void __iwl3945_down(struct iwl_priv *priv)  {  	unsigned long flags; -	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); -	struct ieee80211_conf *conf = NULL; +	int exit_pending;  	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); -	conf = ieee80211_get_hw_conf(priv->hw); +	iwl_scan_cancel_timeout(priv, 200); -	if (!exit_pending) -		set_bit(STATUS_EXIT_PENDING, &priv->status); +	exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); + +	/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set +	 * to prevent rearm timer */ +	if (priv->cfg->ops->lib->recover_from_tx_stall) +		del_timer_sync(&priv->monitor_recover);  	/* Station information will now be cleared in device */ -	iwl_clear_ucode_stations(priv); -	iwl_dealloc_bcast_station(priv); +	iwl_clear_ucode_stations(priv, NULL); +	iwl_dealloc_bcast_stations(priv);  	iwl_clear_driver_stations(priv);  	/* Unblock any waiting calls */ @@ -2619,14 +2637,14 @@ static void __iwl3945_down(struct iwl_priv *priv)  	udelay(5);  	/* Stop the device, and put it in low power state */ -	priv->cfg->ops->lib->apm_ops.stop(priv); +	iwl_apm_stop(priv);   exit:  	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); -	if (priv->ibss_beacon) -		dev_kfree_skb(priv->ibss_beacon); -	priv->ibss_beacon = NULL; +	if (priv->beacon_skb) +		dev_kfree_skb(priv->beacon_skb); +	priv->beacon_skb = NULL;  	/* clear out any free frames */  	iwl3945_clear_free_frames(priv); @@ -2643,11 +2661,33 @@ static void iwl3945_down(struct iwl_priv *priv)  #define MAX_HW_RESTARTS 5 +static int iwl3945_alloc_bcast_station(struct iwl_priv *priv) +{ +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; +	unsigned long flags; +	u8 sta_id; + +	spin_lock_irqsave(&priv->sta_lock, flags); +	sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); +	if (sta_id == IWL_INVALID_STATION) { +		IWL_ERR(priv, "Unable to prepare broadcast station\n"); +		spin_unlock_irqrestore(&priv->sta_lock, flags); + +		return -EINVAL; +	} + +	priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; +	priv->stations[sta_id].used |= IWL_STA_BCAST; +	spin_unlock_irqrestore(&priv->sta_lock, flags); + +	return 0; +} +  static int __iwl3945_up(struct iwl_priv *priv)  {  	int rc, i; -	rc = iwl_alloc_bcast_station(priv, false); +	rc = iwl3945_alloc_bcast_station(priv);  	if (rc)  		return rc; @@ -2799,7 +2839,7 @@ static void iwl3945_rfkill_poll(struct work_struct *data)  } -void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) +int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  {  	struct iwl_host_cmd cmd = {  		.id = REPLY_SCAN_CMD, @@ -2807,61 +2847,19 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  		.flags = CMD_SIZE_HUGE,  	};  	struct iwl3945_scan_cmd *scan; -	struct ieee80211_conf *conf = NULL;  	u8 n_probes = 0;  	enum ieee80211_band band;  	bool is_active = false; +	int ret; -	conf = ieee80211_get_hw_conf(priv->hw); - -	cancel_delayed_work(&priv->scan_check); - -	if (!iwl_is_ready(priv)) { -		IWL_WARN(priv, "request scan called when driver not ready.\n"); -		goto done; -	} - -	/* Make sure the scan wasn't canceled before this queued work -	 * was given the chance to run... */ -	if (!test_bit(STATUS_SCANNING, &priv->status)) -		goto done; - -	/* This should never be called or scheduled if there is currently -	 * a scan active in the hardware. */ -	if (test_bit(STATUS_SCAN_HW, &priv->status)) { -		IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests  " -				"Ignoring second request.\n"); -		goto done; -	} - -	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { -		IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n"); -		goto done; -	} - -	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { -		IWL_DEBUG_HC(priv, -			"Scan request while abort pending. Queuing.\n"); -		goto done; -	} - -	if (iwl_is_rfkill(priv)) { -		IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n"); -		goto done; -	} - -	if (!test_bit(STATUS_READY, &priv->status)) { -		IWL_DEBUG_HC(priv, -			"Scan request while uninitialized. Queuing.\n"); -		goto done; -	} +	lockdep_assert_held(&priv->mutex);  	if (!priv->scan_cmd) {  		priv->scan_cmd = kmalloc(sizeof(struct iwl3945_scan_cmd) +  					 IWL_MAX_SCAN_SIZE, GFP_KERNEL);  		if (!priv->scan_cmd) {  			IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n"); -			goto done; +			return -ENOMEM;  		}  	}  	scan = priv->scan_cmd; @@ -2870,7 +2868,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;  	scan->quiet_time = IWL_ACTIVE_QUIET_TIME; -	if (iwl_is_associated(priv)) { +	if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {  		u16 interval = 0;  		u32 extra;  		u32 suspend_time = 100; @@ -2931,7 +2929,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  	/* We don't build a direct scan probe request; the uCode will do  	 * that based on the direct_mask added to each channel entry */  	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; -	scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; +	scan->tx_cmd.sta_id = priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;  	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;  	/* flags + rate selection */ @@ -2940,25 +2938,25 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  	case IEEE80211_BAND_2GHZ:  		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;  		scan->tx_cmd.rate = IWL_RATE_1M_PLCP; -		scan->good_CRC_th = 0;  		band = IEEE80211_BAND_2GHZ;  		break;  	case IEEE80211_BAND_5GHZ:  		scan->tx_cmd.rate = IWL_RATE_6M_PLCP; -		/* -		 * If active scaning is requested but a certain channel -		 * is marked passive, we can do active scanning if we -		 * detect transmissions. -		 */ -		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : -						IWL_GOOD_CRC_TH_DISABLED;  		band = IEEE80211_BAND_5GHZ;  		break;  	default:  		IWL_WARN(priv, "Invalid scan band\n"); -		goto done; +		return -EIO;  	} +	/* +	 * If active scaning is requested but a certain channel +	 * is marked passive, we can do active scanning if we +	 * detect transmissions. +	 */ +	scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : +					IWL_GOOD_CRC_TH_DISABLED; +  	if (!priv->is_internal_short_scan) {  		scan->tx_cmd.len = cpu_to_le16(  			iwl_fill_probe_req(priv, @@ -2991,7 +2989,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  	if (scan->channel_count == 0) {  		IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); -		goto done; +		return -EIO;  	}  	cmd.len += le16_to_cpu(scan->tx_cmd.len) + @@ -3000,25 +2998,22 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)  	scan->len = cpu_to_le16(cmd.len);  	set_bit(STATUS_SCAN_HW, &priv->status); -	if (iwl_send_cmd_sync(priv, &cmd)) -		goto done; - -	queue_delayed_work(priv->workqueue, &priv->scan_check, -			   IWL_SCAN_CHECK_WATCHDOG); - -	return; +	ret = iwl_send_cmd_sync(priv, &cmd); +	if (ret) +		clear_bit(STATUS_SCAN_HW, &priv->status); +	return ret; +} - done: -	/* can not perform scan make sure we clear scanning -	 * bits from status so next scan request can be performed. -	 * if we dont clear scanning status bit here all next scan -	 * will fail -	*/ -	clear_bit(STATUS_SCAN_HW, &priv->status); -	clear_bit(STATUS_SCANNING, &priv->status); +void iwl3945_post_scan(struct iwl_priv *priv) +{ +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; -	/* inform mac80211 scan aborted */ -	queue_work(priv->workqueue, &priv->abort_scan); +	/* +	 * Since setting the RXON may have been deferred while +	 * performing the scan, fire one off if needed +	 */ +	if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) +		iwl3945_commit_rxon(priv, ctx);  }  static void iwl3945_bg_restart(struct work_struct *data) @@ -3029,8 +3024,10 @@ static void iwl3945_bg_restart(struct work_struct *data)  		return;  	if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { +		struct iwl_rxon_context *ctx;  		mutex_lock(&priv->mutex); -		priv->vif = NULL; +		for_each_context(priv, ctx) +			ctx->vif = NULL;  		priv->is_open = 0;  		mutex_unlock(&priv->mutex);  		iwl3945_down(priv); @@ -3064,6 +3061,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)  {  	int rc = 0;  	struct ieee80211_conf *conf = NULL; +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	if (!vif || !priv->is_open)  		return; @@ -3074,7 +3072,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)  	}  	IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", -			vif->bss_conf.aid, priv->active_rxon.bssid_addr); +			vif->bss_conf.aid, ctx->active.bssid_addr);  	if (test_bit(STATUS_EXIT_PENDING, &priv->status))  		return; @@ -3083,37 +3081,34 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)  	conf = ieee80211_get_hw_conf(priv->hw); -	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; -	iwlcore_commit_rxon(priv); +	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; +	iwl3945_commit_rxon(priv, ctx); -	memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); -	iwl_setup_rxon_timing(priv, vif); -	rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, -			      sizeof(priv->rxon_timing), &priv->rxon_timing); +	rc = iwl_send_rxon_timing(priv, ctx);  	if (rc)  		IWL_WARN(priv, "REPLY_RXON_TIMING failed - "  			    "Attempting to continue.\n"); -	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; +	ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; -	priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid); +	ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);  	IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",  			vif->bss_conf.aid, vif->bss_conf.beacon_int);  	if (vif->bss_conf.use_short_preamble) -		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +		ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;  	else -		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; +		ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; -	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { +	if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {  		if (vif->bss_conf.use_short_slot) -			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; +			ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;  		else -			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; +			ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;  	} -	iwlcore_commit_rxon(priv); +	iwl3945_commit_rxon(priv, ctx);  	switch (vif->type) {  	case NL80211_IFTYPE_STATION: @@ -3212,15 +3207,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)  	priv->is_open = 0; -	if (iwl_is_ready_rf(priv)) { -		/* stop mac, cancel any scan request and clear -		 * RXON_FILTER_ASSOC_MSK BIT -		 */ -		mutex_lock(&priv->mutex); -		iwl_scan_cancel_timeout(priv, 100); -		mutex_unlock(&priv->mutex); -	} -  	iwl3945_down(priv);  	flush_workqueue(priv->workqueue); @@ -3250,48 +3236,45 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)  void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)  { +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	int rc = 0;  	if (test_bit(STATUS_EXIT_PENDING, &priv->status))  		return;  	/* The following should be done only at AP bring up */ -	if (!(iwl_is_associated(priv))) { +	if (!(iwl_is_associated(priv, IWL_RXON_CTX_BSS))) {  		/* RXON - unassoc (to set timing command) */ -		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; -		iwlcore_commit_rxon(priv); +		ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; +		iwl3945_commit_rxon(priv, ctx);  		/* RXON Timing */ -		memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); -		iwl_setup_rxon_timing(priv, vif); -		rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, -				      sizeof(priv->rxon_timing), -				      &priv->rxon_timing); +		rc = iwl_send_rxon_timing(priv, ctx);  		if (rc)  			IWL_WARN(priv, "REPLY_RXON_TIMING failed - "  					"Attempting to continue.\n"); -		priv->staging_rxon.assoc_id = 0; +		ctx->staging.assoc_id = 0;  		if (vif->bss_conf.use_short_preamble) -			priv->staging_rxon.flags |= +			ctx->staging.flags |=  				RXON_FLG_SHORT_PREAMBLE_MSK;  		else -			priv->staging_rxon.flags &= +			ctx->staging.flags &=  				~RXON_FLG_SHORT_PREAMBLE_MSK; -		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { +		if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {  			if (vif->bss_conf.use_short_slot) -				priv->staging_rxon.flags |= +				ctx->staging.flags |=  					RXON_FLG_SHORT_SLOT_MSK;  			else -				priv->staging_rxon.flags &= +				ctx->staging.flags &=  					~RXON_FLG_SHORT_SLOT_MSK;  		}  		/* restore RXON assoc */ -		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; -		iwlcore_commit_rxon(priv); +		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; +		iwl3945_commit_rxon(priv, ctx);  	}  	iwl3945_send_beacon_cmd(priv); @@ -3317,10 +3300,11 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		return -EOPNOTSUPP;  	} -	static_key = !iwl_is_associated(priv); +	static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS);  	if (!static_key) { -		sta_id = iwl_sta_id_or_broadcast(priv, sta); +		sta_id = iwl_sta_id_or_broadcast( +				priv, &priv->contexts[IWL_RXON_CTX_BSS], sta);  		if (sta_id == IWL_INVALID_STATION)  			return -EINVAL;  	} @@ -3371,8 +3355,8 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,  	sta_priv->common.sta_id = IWL_INVALID_STATION; -	ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap, -				     &sta_id); +	ret = iwl_add_station_common(priv, &priv->contexts[IWL_RXON_CTX_BSS], +				     sta->addr, is_ap, sta, &sta_id);  	if (ret) {  		IWL_ERR(priv, "Unable to add station %pM (%d)\n",  			sta->addr, ret); @@ -3399,6 +3383,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,  {  	struct iwl_priv *priv = hw->priv;  	__le32 filter_or = 0, filter_nand = 0; +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  #define CHK(test, flag)	do { \  	if (*total_flags & (test))		\ @@ -3418,8 +3403,8 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,  	mutex_lock(&priv->mutex); -	priv->staging_rxon.filter_flags &= ~filter_nand; -	priv->staging_rxon.filter_flags |= filter_or; +	ctx->staging.filter_flags &= ~filter_nand; +	ctx->staging.filter_flags |= filter_or;  	/*  	 * Committing directly here breaks for some reason, @@ -3533,8 +3518,9 @@ static ssize_t show_flags(struct device *d,  			  struct device_attribute *attr, char *buf)  {  	struct iwl_priv *priv = dev_get_drvdata(d); +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; -	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); +	return sprintf(buf, "0x%04X\n", ctx->active.flags);  }  static ssize_t store_flags(struct device *d, @@ -3543,17 +3529,18 @@ static ssize_t store_flags(struct device *d,  {  	struct iwl_priv *priv = dev_get_drvdata(d);  	u32 flags = simple_strtoul(buf, NULL, 0); +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	mutex_lock(&priv->mutex); -	if (le32_to_cpu(priv->staging_rxon.flags) != flags) { +	if (le32_to_cpu(ctx->staging.flags) != flags) {  		/* Cancel any currently running scans... */  		if (iwl_scan_cancel_timeout(priv, 100))  			IWL_WARN(priv, "Could not cancel scan.\n");  		else {  			IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n",  				       flags); -			priv->staging_rxon.flags = cpu_to_le32(flags); -			iwlcore_commit_rxon(priv); +			ctx->staging.flags = cpu_to_le32(flags); +			iwl3945_commit_rxon(priv, ctx);  		}  	}  	mutex_unlock(&priv->mutex); @@ -3567,9 +3554,10 @@ static ssize_t show_filter_flags(struct device *d,  				 struct device_attribute *attr, char *buf)  {  	struct iwl_priv *priv = dev_get_drvdata(d); +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	return sprintf(buf, "0x%04X\n", -		le32_to_cpu(priv->active_rxon.filter_flags)); +		le32_to_cpu(ctx->active.filter_flags));  }  static ssize_t store_filter_flags(struct device *d, @@ -3577,19 +3565,20 @@ static ssize_t store_filter_flags(struct device *d,  				  const char *buf, size_t count)  {  	struct iwl_priv *priv = dev_get_drvdata(d); +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	u32 filter_flags = simple_strtoul(buf, NULL, 0);  	mutex_lock(&priv->mutex); -	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { +	if (le32_to_cpu(ctx->staging.filter_flags) != filter_flags) {  		/* Cancel any currently running scans... */  		if (iwl_scan_cancel_timeout(priv, 100))  			IWL_WARN(priv, "Could not cancel scan.\n");  		else {  			IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = "  				       "0x%04X\n", filter_flags); -			priv->staging_rxon.filter_flags = +			ctx->staging.filter_flags =  				cpu_to_le32(filter_flags); -			iwlcore_commit_rxon(priv); +			iwl3945_commit_rxon(priv, ctx);  		}  	}  	mutex_unlock(&priv->mutex); @@ -3637,8 +3626,9 @@ static ssize_t store_measurement(struct device *d,  				 const char *buf, size_t count)  {  	struct iwl_priv *priv = dev_get_drvdata(d); +	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];  	struct ieee80211_measurement_params params = { -		.channel = le16_to_cpu(priv->active_rxon.channel), +		.channel = le16_to_cpu(ctx->active.channel),  		.start_time = cpu_to_le64(priv->_3945.last_tsf),  		.duration = cpu_to_le16(1),  	}; @@ -3785,10 +3775,8 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)  	INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);  	INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);  	INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll); -	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); -	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); + +	iwl_setup_scan_deferred_work(priv);  	iwl3945_hw_setup_deferred_work(priv); @@ -3808,12 +3796,10 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)  	iwl3945_hw_cancel_deferred_work(priv);  	cancel_delayed_work_sync(&priv->init_alive_start); -	cancel_delayed_work(&priv->scan_check);  	cancel_delayed_work(&priv->alive_start); -	cancel_work_sync(&priv->start_internal_scan);  	cancel_work_sync(&priv->beacon_update); -	if (priv->cfg->ops->lib->recover_from_tx_stall) -		del_timer_sync(&priv->monitor_recover); + +	iwl_cancel_scan_deferred_work(priv);  }  static struct attribute *iwl3945_sysfs_entries[] = { @@ -3853,6 +3839,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {  	.hw_scan = iwl_mac_hw_scan,  	.sta_add = iwl3945_mac_sta_add,  	.sta_remove = iwl_mac_sta_remove, +	.tx_last_beacon = iwl_mac_tx_last_beacon,  };  static int iwl3945_init_drv(struct iwl_priv *priv) @@ -3861,7 +3848,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)  	struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom;  	priv->retry_rate = 1; -	priv->ibss_beacon = NULL; +	priv->beacon_skb = NULL;  	spin_lock_init(&priv->sta_lock);  	spin_lock_init(&priv->hcmd_lock); @@ -3928,13 +3915,12 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)  	hw->flags = IEEE80211_HW_SIGNAL_DBM |  		    IEEE80211_HW_SPECTRUM_MGMT; -	if (!priv->cfg->broken_powersave) +	if (!priv->cfg->base_params->broken_powersave)  		hw->flags |= IEEE80211_HW_SUPPORTS_PS |  			     IEEE80211_HW_SUPPORTS_DYNAMIC_PS;  	hw->wiphy->interface_modes = -		BIT(NL80211_IFTYPE_STATION) | -		BIT(NL80211_IFTYPE_ADHOC); +		priv->contexts[IWL_RXON_CTX_BSS].interface_modes;  	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |  			    WIPHY_FLAG_DISABLE_BEACON_HINTS; @@ -3966,7 +3952,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)  static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  { -	int err = 0; +	int err = 0, i;  	struct iwl_priv *priv;  	struct ieee80211_hw *hw;  	struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); @@ -3988,12 +3974,33 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e  	priv = hw->priv;  	SET_IEEE80211_DEV(hw, &pdev->dev); +	priv->cmd_queue = IWL39_CMD_QUEUE_NUM; + +	/* 3945 has only one valid context */ +	priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); + +	for (i = 0; i < NUM_IWL_RXON_CTX; i++) +		priv->contexts[i].ctxid = i; + +	priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; +	priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; +	priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; +	priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; +	priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; +	priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; +	priv->contexts[IWL_RXON_CTX_BSS].interface_modes = +		BIT(NL80211_IFTYPE_STATION) | +		BIT(NL80211_IFTYPE_ADHOC); +	priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; +	priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; +	priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; +  	/*  	 * Disabling hardware scan means that mac80211 will perform scans  	 * "the hard way", rather than using device's scan.  	 */  	if (iwl3945_mod_params.disable_hw_scan) { -		IWL_DEBUG_INFO(priv, "Disabling hw_scan\n"); +		IWL_ERR(priv, "sw scan support is deprecated\n");  		iwl3945_hw_ops.hw_scan = NULL;  	} @@ -4009,6 +4016,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e  	/***************************  	 * 2. Initializing PCI bus  	 * *************************/ +	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | +				PCIE_LINK_STATE_CLKPM); +  	if (pci_enable_device(pdev)) {  		err = -ENODEV;  		goto out_ieee80211_free_hw; @@ -4120,7 +4130,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e  	}  	iwl_set_rxon_channel(priv, -			     &priv->bands[IEEE80211_BAND_2GHZ].channels[5]); +			     &priv->bands[IEEE80211_BAND_2GHZ].channels[5], +			     &priv->contexts[IWL_RXON_CTX_BSS]);  	iwl3945_setup_deferred_work(priv);  	iwl3945_setup_rx_handlers(priv);  	iwl_power_initialize(priv); @@ -4201,7 +4212,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)  	 * paths to avoid running iwl_down() at all before leaving driver.  	 * This (inexpensive) call *makes sure* device is reset.  	 */ -	priv->cfg->ops->lib->apm_ops.stop(priv); +	iwl_apm_stop(priv);  	/* make sure we flush any pending irq or  	 * tasklet for the driver @@ -4245,8 +4256,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)  	iwl_free_channel_map(priv);  	iwlcore_free_geos(priv);  	kfree(priv->scan_cmd); -	if (priv->ibss_beacon) -		dev_kfree_skb(priv->ibss_beacon); +	if (priv->beacon_skb) +		dev_kfree_skb(priv->beacon_skb);  	ieee80211_free_hw(priv->hw);  } @@ -4314,7 +4325,8 @@ MODULE_PARM_DESC(debug, "debug output mask");  #endif  module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan,  		   int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); +MODULE_PARM_DESC(disable_hw_scan, +		 "disable hardware scanning (default 0) (deprecated)");  module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);  MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");  |