Пример #1
0
/**
 * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
 *
 * pre-requirements:
 *  1. acquire mutex before calling
 *  2. make sure rf is on and not in exit state
 */
int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk)
{
	struct iwl_txfifo_flush_cmd_v3 flush_cmd_v3 = {
		.flush_control = cpu_to_le16(IWL_DROP_ALL),
	};
	struct iwl_txfifo_flush_cmd_v2 flush_cmd_v2 = {
		.flush_control = cpu_to_le16(IWL_DROP_ALL),
	};

	u32 queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
			    IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | IWL_SCD_MGMT_MSK;

	if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
		queue_control |= IWL_PAN_SCD_VO_MSK | IWL_PAN_SCD_VI_MSK |
				 IWL_PAN_SCD_BE_MSK | IWL_PAN_SCD_BK_MSK |
				 IWL_PAN_SCD_MGMT_MSK |
				 IWL_PAN_SCD_MULTICAST_MSK;

	if (priv->nvm_data->sku_cap_11n_enable)
		queue_control |= IWL_AGG_TX_QUEUE_MSK;

	if (scd_q_msk)
		queue_control = scd_q_msk;

	IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", queue_control);
	flush_cmd_v3.queue_control = cpu_to_le32(queue_control);
	flush_cmd_v2.queue_control = cpu_to_le16((u16)queue_control);

	if (IWL_UCODE_API(priv->fw->ucode_ver) > 2)
		return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0,
					    sizeof(flush_cmd_v3),
					    &flush_cmd_v3);
	return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0,
				    sizeof(flush_cmd_v2), &flush_cmd_v2);
}
static int iwlagn_disable_pan(struct iwl_priv *priv,
			      struct iwl_rxon_context *ctx,
			      struct iwl_rxon_cmd *send)
{
	struct iwl_notification_wait disable_wait;
	__le32 old_filter = send->filter_flags;
	u8 old_dev_type = send->dev_type;
	int ret;

	iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
				   REPLY_WIPAN_DEACTIVATION_COMPLETE,
				   NULL, NULL);

	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
	send->dev_type = RXON_DEV_TYPE_P2P;
	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
				CMD_SYNC, sizeof(*send), send);

	send->filter_flags = old_filter;
	send->dev_type = old_dev_type;

	if (ret) {
		IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
		iwl_remove_notification(&priv->notif_wait, &disable_wait);
	} else {
		ret = iwl_wait_notification(&priv->notif_wait,
					    &disable_wait, HZ);
		if (ret)
			IWL_ERR(priv, "Timed out waiting for PAN disable\n");
	}

	return ret;
}
static void iwlagn_update_qos(struct iwl_priv *priv,
			      struct iwl_rxon_context *ctx)
{
	int ret;

	if (!ctx->is_active)
		return;

	ctx->qos_data.def_qos_parm.qos_flags = 0;

	if (ctx->qos_data.qos_active)
		ctx->qos_data.def_qos_parm.qos_flags |=
			QOS_PARAM_FLG_UPDATE_EDCA_MSK;

	if (ctx->ht.enabled)
		ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;

	IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
		      ctx->qos_data.qos_active,
		      ctx->qos_data.def_qos_parm.qos_flags);

	ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
			       sizeof(struct iwl_qosparam_cmd),
			       &ctx->qos_data.def_qos_parm);
	if (ret)
		IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
}
static int iwlagn_rxon_connect(struct iwl_priv *priv,
			       struct iwl_rxon_context *ctx)
{
	int ret;
	struct iwl_rxon_cmd *active = (void *)&ctx->active;

	
	if (ctx->ctxid == IWL_RXON_CTX_BSS) {
		ret = iwl_send_rxon_timing(priv, ctx);
		if (ret) {
			IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
			return ret;
		}
	}
	
	iwlagn_update_qos(priv, ctx);

	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
		ret = iwlagn_update_beacon(priv, ctx->vif);
		if (ret) {
			IWL_ERR(priv,
				"Error sending required beacon (%d)!\n",
				ret);
			return ret;
		}
	}

	priv->start_calib = 0;
	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
		      sizeof(struct iwl_rxon_cmd), &ctx->staging);
	if (ret) {
		IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
		return ret;
	}
	memcpy(active, &ctx->staging, sizeof(*active));

	
	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
		if (iwlagn_update_beacon(priv, ctx->vif))
			IWL_ERR(priv, "Error sending IBSS beacon\n");
	iwl_init_sensitivity(priv);

	ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
	if (ret) {
		IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
		return ret;
	}

	if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
	    cfg(priv)->ht_params && cfg(priv)->ht_params->smps_mode)
		ieee80211_request_smps(ctx->vif,
				       cfg(priv)->ht_params->smps_mode);

	return 0;
}
static int iwlagn_disconn_pan(struct iwl_priv *priv,
			      struct iwl_rxon_context *ctx,
			      struct iwl_rxon_cmd *send)
{
	__le32 old_filter = send->filter_flags;
	int ret;

	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
				sizeof(*send), send);

	send->filter_flags = old_filter;

	return ret;
}
Пример #6
0
static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
{
	IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
	IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
	IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
	IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
	IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n",
			le32_to_cpu(cmd->sleep_interval[0]),
			le32_to_cpu(cmd->sleep_interval[1]),
			le32_to_cpu(cmd->sleep_interval[2]),
			le32_to_cpu(cmd->sleep_interval[3]),
			le32_to_cpu(cmd->sleep_interval[4]));

	return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, 0,
				sizeof(struct iwl_powertable_cmd), cmd);
}
static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
			   struct iwl_rxon_context *ctx)
{
	int ret = 0;
	struct iwl_rxon_assoc_cmd rxon_assoc;
	const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
	const struct iwl_rxon_cmd *rxon2 = &ctx->active;

	if ((rxon1->flags == rxon2->flags) &&
	    (rxon1->filter_flags == rxon2->filter_flags) &&
	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
	    (rxon1->ofdm_ht_single_stream_basic_rates ==
	     rxon2->ofdm_ht_single_stream_basic_rates) &&
	    (rxon1->ofdm_ht_dual_stream_basic_rates ==
	     rxon2->ofdm_ht_dual_stream_basic_rates) &&
	    (rxon1->ofdm_ht_triple_stream_basic_rates ==
	     rxon2->ofdm_ht_triple_stream_basic_rates) &&
	    (rxon1->acquisition_data == rxon2->acquisition_data) &&
	    (rxon1->rx_chain == rxon2->rx_chain) &&
	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
		IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
		return 0;
	}

	rxon_assoc.flags = ctx->staging.flags;
	rxon_assoc.filter_flags = ctx->staging.filter_flags;
	rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
	rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
	rxon_assoc.reserved1 = 0;
	rxon_assoc.reserved2 = 0;
	rxon_assoc.reserved3 = 0;
	rxon_assoc.ofdm_ht_single_stream_basic_rates =
	    ctx->staging.ofdm_ht_single_stream_basic_rates;
	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
	    ctx->staging.ofdm_ht_dual_stream_basic_rates;
	rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
	rxon_assoc.ofdm_ht_triple_stream_basic_rates =
		 ctx->staging.ofdm_ht_triple_stream_basic_rates;
	rxon_assoc.acquisition_data = ctx->staging.acquisition_data;

	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
				CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
	return ret;
}
static int iwlagn_disable_bss(struct iwl_priv *priv,
			      struct iwl_rxon_context *ctx,
			      struct iwl_rxon_cmd *send)
{
	__le32 old_filter = send->filter_flags;
	int ret;

	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
				CMD_SYNC, sizeof(*send), send);

	send->filter_flags = old_filter;

	if (ret)
		IWL_DEBUG_QUIET_RFKILL(priv,
			"Error clearing ASSOC_MSK on BSS (%d)\n", ret);

	return ret;
}
Пример #9
0
int iwlagn_send_tx_power(struct iwl_priv *priv)
{
	struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
	u8 tx_ant_cfg_cmd;

	if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
		      "TX Power requested while scanning!\n"))
		return -EAGAIN;

	/* half dBm need to multiply */
	tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);

	if (tx_power_cmd.global_lmt > priv->nvm_data->max_tx_pwr_half_dbm) {
		/*
		 * For the newer devices which using enhanced/extend tx power
		 * table in EEPROM, the format is in half dBm. driver need to
		 * convert to dBm format before report to mac80211.
		 * By doing so, there is a possibility of 1/2 dBm resolution
		 * lost. driver will perform "round-up" operation before
		 * reporting, but it will cause 1/2 dBm tx power over the
		 * regulatory limit. Perform the checking here, if the
		 * "tx_power_user_lmt" is higher than EEPROM value (in
		 * half-dBm format), lower the tx power based on EEPROM
		 */
		tx_power_cmd.global_lmt =
			priv->nvm_data->max_tx_pwr_half_dbm;
	}
	tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
	tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;

	if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
	else
		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;

	return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, 0,
			sizeof(tx_power_cmd), &tx_power_cmd);
}
static int iwlagn_rxon_connect(struct iwl_priv *priv,
			       struct iwl_rxon_context *ctx)
{
	int ret;
	struct iwl_rxon_cmd *active = (void *)&ctx->active;

	/* RXON timing must be before associated RXON */
	if (ctx->ctxid == IWL_RXON_CTX_BSS) {
		ret = iwl_send_rxon_timing(priv, ctx);
		if (ret) {
			IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
			return ret;
		}
	}
	/* QoS info may be cleared by previous un-assoc RXON */
	iwlagn_update_qos(priv, ctx);

	/*
	 * We'll run into this code path when beaconing is
	 * enabled, but then we also need to send the beacon
	 * to the device.
	 */
	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
		ret = iwlagn_update_beacon(priv, ctx->vif);
		if (ret) {
			IWL_ERR(priv,
				"Error sending required beacon (%d)!\n",
				ret);
			return ret;
		}
	}

	priv->start_calib = 0;
	/*
	 * Apply the new configuration.
	 *
	 * Associated RXON doesn't clear the station table in uCode,
	 * so we don't need to restore stations etc. after this.
	 */
	ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
		      sizeof(struct iwl_rxon_cmd), &ctx->staging);
	if (ret) {
		IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
		return ret;
	}
	memcpy(active, &ctx->staging, sizeof(*active));

	/* IBSS beacon needs to be sent after setting assoc */
	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
		if (iwlagn_update_beacon(priv, ctx->vif))
			IWL_ERR(priv, "Error sending IBSS beacon\n");
	iwl_init_sensitivity(priv);

	/*
	 * If we issue a new RXON command which required a tune then
	 * we must send a new TXPOWER command or we won't be able to
	 * Tx any frames.
	 *
	 * It's expected we set power here if channel is changing.
	 */
	ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
	if (ret) {
		IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
		return ret;
	}

	if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
	    cfg(priv)->ht_params && cfg(priv)->ht_params->smps_mode)
		ieee80211_request_smps(ctx->vif,
				       cfg(priv)->ht_params->smps_mode);

	return 0;
}
Пример #11
0
static int iwl_send_rxon_timing(struct iwl_priv *priv,
				struct iwl_rxon_context *ctx)
{
	u64 tsf;
	s32 interval_tm, rem;
	struct ieee80211_conf *conf = NULL;
	u16 beacon_int;
	struct ieee80211_vif *vif = ctx->vif;

	conf = &priv->hw->conf;

	lockdep_assert_held(&priv->mutex);

	memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));

	ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
	ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);

	beacon_int = vif ? vif->bss_conf.beacon_int : 0;

	/*
	 * TODO: For IBSS we need to get atim_window from mac80211,
	 *	 for now just always use 0
	 */
	ctx->timing.atim_window = 0;

	if (ctx->ctxid == IWL_RXON_CTX_PAN &&
	    (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
	    iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
	    priv->contexts[IWL_RXON_CTX_BSS].vif &&
	    priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
		ctx->timing.beacon_interval =
			priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
		beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
	} else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
		   iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
		   priv->contexts[IWL_RXON_CTX_PAN].vif &&
		   priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
		   (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
		    !ctx->vif->bss_conf.beacon_int)) {
		ctx->timing.beacon_interval =
			priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
		beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
	} else {
		beacon_int = iwl_adjust_beacon_interval(beacon_int,
			IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
		ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
	}

	ctx->beacon_int = beacon_int;

	tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
	interval_tm = beacon_int * TIME_UNIT;
	rem = do_div(tsf, interval_tm);
	ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);

	ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;

	IWL_DEBUG_ASSOC(priv,
			"beacon interval %d beacon timer %d beacon tim %d\n",
			le16_to_cpu(ctx->timing.beacon_interval),
			le32_to_cpu(ctx->timing.beacon_init_val),
			le16_to_cpu(ctx->timing.atim_window));

	return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
				0, sizeof(ctx->timing), &ctx->timing);
}
Пример #12
0
void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
{
	struct iwl_basic_bt_cmd basic = {
		.max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
		.bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
		.bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
		.bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
	};
	struct iwl_bt_cmd_v1 bt_cmd_v1;
	struct iwl_bt_cmd_v2 bt_cmd_v2;
	int ret;

	BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
			sizeof(basic.bt3_lookup_table));

	if (priv->lib->bt_params) {
		/*
		 * newer generation of devices (2000 series and newer)
		 * use the version 2 of the bt command
		 * we need to make sure sending the host command
		 * with correct data structure to avoid uCode assert
		 */
		if (priv->lib->bt_params->bt_session_2) {
			bt_cmd_v2.prio_boost = cpu_to_le32(
				priv->lib->bt_params->bt_prio_boost);
			bt_cmd_v2.tx_prio_boost = 0;
			bt_cmd_v2.rx_prio_boost = 0;
		} else {
			/* older version only has 8 bits */
			WARN_ON(priv->lib->bt_params->bt_prio_boost & ~0xFF);
			bt_cmd_v1.prio_boost =
				priv->lib->bt_params->bt_prio_boost;
			bt_cmd_v1.tx_prio_boost = 0;
			bt_cmd_v1.rx_prio_boost = 0;
		}
	} else {
		IWL_ERR(priv, "failed to construct BT Coex Config\n");
		return;
	}

	/*
	 * Possible situations when BT needs to take over for receive,
	 * at the same time where STA needs to response to AP's frame(s),
	 * reduce the tx power of the required response frames, by that,
	 * allow the concurrent BT receive & WiFi transmit
	 * (BT - ANT A, WiFi -ANT B), without interference to one another
	 *
	 * Reduced tx power apply to control frames only (ACK/Back/CTS)
	 * when indicated by the BT config command
	 */
	basic.kill_ack_mask = priv->kill_ack_mask;
	basic.kill_cts_mask = priv->kill_cts_mask;
	if (priv->reduced_txpower)
		basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
	basic.valid = priv->bt_valid;

	/*
	 * Configure BT coex mode to "no coexistence" when the
	 * user disabled BT coexistence, we have no interface
	 * (might be in monitor mode), or the interface is in
	 * IBSS mode (no proper uCode support for coex then).
	 */
	if (!iwlwifi_mod_params.bt_coex_active ||
	    priv->iw_mode == NL80211_IFTYPE_ADHOC) {
		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
	} else {
		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
					IWLAGN_BT_FLAG_COEX_MODE_SHIFT;

		if (!priv->bt_enable_pspoll)
			basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
		else
			basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;

		if (priv->bt_ch_announce)
			basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
		IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags);
	}
	priv->bt_enable_flag = basic.flags;
	if (priv->bt_full_concurrent)
		memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
			sizeof(iwlagn_concurrent_lookup));
	else
		memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
			sizeof(iwlagn_def_3w_lookup));

	IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n",
		       basic.flags ? "active" : "disabled",
		       priv->bt_full_concurrent ?
		       "full concurrency" : "3-wire");

	if (priv->lib->bt_params->bt_session_2) {
		memcpy(&bt_cmd_v2.basic, &basic,
			sizeof(basic));
		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
			0, sizeof(bt_cmd_v2), &bt_cmd_v2);
	} else {
		memcpy(&bt_cmd_v1.basic, &basic,
			sizeof(basic));
		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
			0, sizeof(bt_cmd_v1), &bt_cmd_v1);
	}
	if (ret)
		IWL_ERR(priv, "failed to send BT Coex Config\n");

}