static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
				     struct ieee80211_vif *vif)
{
	struct iwl_mac_power_cmd cmd = {};
	struct iwl_mvm_vif *mvmvif __maybe_unused =
		iwl_mvm_vif_from_mac80211(vif);

	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
		return 0;

	cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
							   mvmvif->color));

	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
		cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);

#ifdef CONFIG_IWLWIFI_DEBUGFS
	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
	    mvmvif->dbgfs_pm.disable_power_off)
		cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
	iwl_mvm_power_log(mvm, &cmd);

	return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC,
				    sizeof(cmd), &cmd);
}
Beispiel #2
0
void
iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
					 struct iwl_beacon_filter_cmd *cmd)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;

	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA)
		cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA)
		cmd->bf_roaming_energy_delta =
				cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE)
		cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD)
		cmd->bf_temp_threshold =
				cpu_to_le32(dbgfs_bf->bf_temp_threshold);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER)
		cmd->bf_temp_fast_filter =
				cpu_to_le32(dbgfs_bf->bf_temp_fast_filter);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER)
		cmd->bf_temp_slow_filter =
				cpu_to_le32(dbgfs_bf->bf_temp_slow_filter);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG)
		cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER)
		cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER)
		cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT)
		cmd->ba_enable_beacon_abort =
				cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort);
}
Beispiel #3
0
static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
					      struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	mvmvif->pm_enabled = false;
}
Beispiel #4
0
void
iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
					 struct iwl_beacon_filter_cmd *cmd)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;

	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA)
		cmd->bf_energy_delta = dbgfs_bf->bf_energy_delta;
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA)
		cmd->bf_roaming_energy_delta =
				 dbgfs_bf->bf_roaming_energy_delta;
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE)
		cmd->bf_roaming_state = dbgfs_bf->bf_roaming_state;
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMPERATURE_DELTA)
		cmd->bf_temperature_delta = dbgfs_bf->bf_temperature_delta;
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG)
		cmd->bf_debug_flag = dbgfs_bf->bf_debug_flag;
	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER)
		cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER)
		cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer);
	if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT)
		cmd->ba_enable_beacon_abort = dbgfs_bf->ba_enable_beacon_abort;
}
Beispiel #5
0
static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
					 struct iwl_time_quota_cmd *cmd)
{
#ifdef CONFIG_NL80211_TESTMODE
	struct iwl_mvm_vif *mvmvif;
	int i, phy_id = -1, beacon_int = 0;

	if (!mvm->noa_duration || !mvm->noa_vif)
		return;

	mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif);
	if (!mvmvif->ap_ibss_active)
		return;

	phy_id = mvmvif->phy_ctxt->id;
	beacon_int = mvm->noa_vif->bss_conf.beacon_int;

	for (i = 0; i < MAX_BINDINGS; i++) {
		u32 id_n_c = le32_to_cpu(cmd->quotas[i].id_and_color);
		u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS;
		u32 quota = le32_to_cpu(cmd->quotas[i].quota);

		if (id != phy_id)
			continue;

		quota *= (beacon_int - mvm->noa_duration);
		quota /= beacon_int;

		cmd->quotas[i].quota = cpu_to_le32(quota);
	}
#endif
}
Beispiel #6
0
static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
				       struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
		    ETH_ALEN))
		return false;

	if (vif->p2p &&
	    !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
		return false;
	/*
	 * Avoid using uAPSD if P2P client is associated to GO that uses
	 * opportunistic power save. This is due to current FW limitation.
	 */
	if (vif->p2p &&
	    (vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
	    IEEE80211_P2P_OPPPS_ENABLE_BIT))
		return false;

	/*
	 * Avoid using uAPSD if client is in DCM -
	 * low latency issue in Miracast
	 */
	if (iwl_mvm_phy_ctx_count(mvm) >= 2)
		return false;

	return true;
}
Beispiel #7
0
static ssize_t iwl_dbgfs_reduced_txp_write(struct ieee80211_vif *vif,
					   char *buf, size_t count,
					   loff_t *ppos)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_mvm *mvm = mvmvif->mvm;
	struct iwl_mvm_sta *mvmsta;
	bool reduced_tx_power;
	int ret;

	if (mvmvif->ap_sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))
		return -ENOTCONN;

	if (strtobool(buf, &reduced_tx_power) != 0)
		return -EINVAL;

	mutex_lock(&mvm->mutex);

	mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
	if (IS_ERR_OR_NULL(mvmsta)) {
		mutex_unlock(&mvm->mutex);
		return -ENOTCONN;
	}

	mvmsta->bt_reduced_txpower_dbg = false;
	ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
					  reduced_tx_power);
	if (!ret)
		mvmsta->bt_reduced_txpower_dbg = true;

	mutex_unlock(&mvm->mutex);

	return ret ? : count;
}
Beispiel #8
0
static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
        struct ieee80211_vif *vif,
        struct ieee80211_chanctx_conf *ctx)
{
    struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

    mutex_lock(&mvm->mutex);

    iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);

    if (vif->type == NL80211_IFTYPE_AP)
        goto out_unlock;

    iwl_mvm_binding_remove_vif(mvm, vif);
    switch (vif->type) {
    case NL80211_IFTYPE_MONITOR:
        iwl_mvm_update_quotas(mvm, vif);
        break;
    default:
        break;
    }

out_unlock:
    mvmvif->phy_ctxt = NULL;
    mutex_unlock(&mvm->mutex);
}
Beispiel #9
0
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
	struct iwl_powertable_cmd cmd = {};
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	if (!iwlwifi_mod_params.power_save) {
		IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
		return 0;
	}

	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
		return 0;

	cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
							    mvmvif->color));
	cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);

	IWL_DEBUG_POWER(mvm,
			"Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
			cmd.id_and_color, iwlmvm_mod_params.power_scheme,
			le16_to_cpu(cmd.flags));

	return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
				    sizeof(cmd), &cmd);
}
Beispiel #10
0
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct iwl_device_cmd *dev_cmd;
	struct iwl_tx_cmd *tx_cmd;
	u8 sta_id;

	if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU))
		return -1;

	if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
			 (!info->control.vif ||
			  info->hw_queue != info->control.vif->cab_queue)))
		return -1;

	/*
	 * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used
	 * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel
	 * queue. STATION (HS2.0) uses the auxiliary context of the FW,
	 * and hence needs to be sent on the aux queue
	 */
	if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
	    info->control.vif->type == NL80211_IFTYPE_STATION)
		IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue;

	/*
	 * If the interface on which frame is sent is the P2P_DEVICE
	 * or an AP/GO interface use the broadcast station associated
	 * with it; otherwise use the AUX station.
	 */
	if (info->control.vif &&
	    (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
	     info->control.vif->type == NL80211_IFTYPE_AP)) {
		struct iwl_mvm_vif *mvmvif =
			iwl_mvm_vif_from_mac80211(info->control.vif);
		sta_id = mvmvif->bcast_sta.sta_id;
	} else {
		sta_id = mvm->aux_sta.sta_id;
	}

	IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue);

	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id);
	if (!dev_cmd)
		return -1;

	/* From now on, we cannot access info->control */
	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;

	/* Copy MAC header from skb into command buffer */
	memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control));

	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) {
		iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
		return -1;
	}

	return 0;
}
Beispiel #11
0
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

    if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
               ETH_ALEN))
        memset(mvmvif->uapsd_misbehaving_bssid, 0, ETH_ALEN);
}
Beispiel #12
0
static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
					 char __user *user_buf,
					 size_t count, loff_t *ppos)
{
	struct ieee80211_vif *vif = file->private_data;
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_mvm *mvm = mvmvif->mvm;
	u8 ap_sta_id;
	struct ieee80211_chanctx_conf *chanctx_conf;
	char buf[512];
	int bufsz = sizeof(buf);
	int pos = 0;
	int i;

	mutex_lock(&mvm->mutex);

	ap_sta_id = mvmvif->ap_sta_id;

	pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
			 mvmvif->id, mvmvif->color);
	pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
			 vif->bss_conf.bssid);
	pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
	for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
		pos += scnprintf(buf+pos, bufsz-pos,
				 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
				 i, mvmvif->queue_params[i].txop,
				 mvmvif->queue_params[i].cw_min,
				 mvmvif->queue_params[i].cw_max,
				 mvmvif->queue_params[i].aifs,
				 mvmvif->queue_params[i].uapsd);

	if (vif->type == NL80211_IFTYPE_STATION &&
	    ap_sta_id != IWL_MVM_STATION_COUNT) {
		struct ieee80211_sta *sta;
		struct iwl_mvm_sta *mvm_sta;

		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
						lockdep_is_held(&mvm->mutex));
		mvm_sta = (void *)sta->drv_priv;
		pos += scnprintf(buf+pos, bufsz-pos,
				 "ap_sta_id %d - reduced Tx power %d\n",
				 ap_sta_id, mvm_sta->bt_reduced_txpower);
	}

	rcu_read_lock();
	chanctx_conf = rcu_dereference(vif->chanctx_conf);
	if (chanctx_conf)
		pos += scnprintf(buf+pos, bufsz-pos,
				 "idle rx chains %d, active rx chains: %d\n",
				 chanctx_conf->rx_chains_static,
				 chanctx_conf->rx_chains_dynamic);
	rcu_read_unlock();

	mutex_unlock(&mvm->mutex);

	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
Beispiel #13
0
static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
				 struct ieee80211_vif *vif,
				 enum iwl_dbgfs_pm_mask param, int val)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;

	dbgfs_pm->mask |= param;

	switch (param) {
	case MVM_DEBUGFS_PM_KEEP_ALIVE: {
		struct ieee80211_hw *hw = mvm->hw;
		int dtimper = hw->conf.ps_dtim_period ?: 1;
		int dtimper_msec = dtimper * vif->bss_conf.beacon_int;

		IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
		if (val * MSEC_PER_SEC < 3 * dtimper_msec)
			IWL_WARN(mvm,
				 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
				 val * MSEC_PER_SEC, 3 * dtimper_msec);
		dbgfs_pm->keep_alive_seconds = val;
		break;
	}
	case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
		IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
				val ? "enabled" : "disabled");
		dbgfs_pm->skip_over_dtim = val;
		break;
	case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
		IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
		dbgfs_pm->skip_dtim_periods = val;
		break;
	case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
		IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
		dbgfs_pm->rx_data_timeout = val;
		break;
	case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
		IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
		dbgfs_pm->tx_data_timeout = val;
		break;
	case MVM_DEBUGFS_PM_LPRX_ENA:
		IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
		dbgfs_pm->lprx_ena = val;
		break;
	case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
		IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
		dbgfs_pm->lprx_rssi_threshold = val;
		break;
	case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
		IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
		dbgfs_pm->snooze_ena = val;
		break;
	case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
		IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
		dbgfs_pm->uapsd_misbehaving = val;
		break;
	}
}
Beispiel #14
0
static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
					 size_t count, loff_t *ppos)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_mvm *mvm = mvmvif->mvm;
	enum iwl_dbgfs_pm_mask param;
	int val, ret;

	if (!strncmp("keep_alive=", buf, 11)) {
		if (sscanf(buf + 11, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_KEEP_ALIVE;
	} else if (!strncmp("skip_over_dtim=", buf, 15)) {
		if (sscanf(buf + 15, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
	} else if (!strncmp("skip_dtim_periods=", buf, 18)) {
		if (sscanf(buf + 18, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
	} else if (!strncmp("rx_data_timeout=", buf, 16)) {
		if (sscanf(buf + 16, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
	} else if (!strncmp("tx_data_timeout=", buf, 16)) {
		if (sscanf(buf + 16, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
	} else if (!strncmp("lprx=", buf, 5)) {
		if (sscanf(buf + 5, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_LPRX_ENA;
	} else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
		if (sscanf(buf + 20, "%d", &val) != 1)
			return -EINVAL;
		if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
		    POWER_LPRX_RSSI_THRESHOLD_MIN)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
	} else if (!strncmp("snooze_enable=", buf, 14)) {
		if (sscanf(buf + 14, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
	} else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
		if (sscanf(buf + 18, "%d", &val) != 1)
			return -EINVAL;
		param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
	} else {
		return -EINVAL;
	}

	mutex_lock(&mvm->mutex);
	iwl_dbgfs_update_pm(mvm, vif, param, val);
	ret = iwl_mvm_power_update_mac(mvm, vif);
	mutex_unlock(&mvm->mutex);

	return ret ?: count;
}
Beispiel #15
0
static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
				   struct ieee80211_vif *vif)
{
	struct iwl_mvm_quota_iterator_data *data = _data;
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	u16 id;

	/*
	 * We'll account for the new interface (if any) below,
	 * skip it here in case we're not called from within
	 * the add_interface callback (otherwise it won't show
	 * up in iteration)
	 */
	if (vif == data->new_vif)
		return;

	if (!mvmvif->phy_ctxt)
		return;

	/* currently, PHY ID == binding ID */
	id = mvmvif->phy_ctxt->id;

	/* need at least one binding per PHY */
	BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);

	if (WARN_ON_ONCE(id >= MAX_BINDINGS))
		return;

	if (data->colors[id] < 0)
		data->colors[id] = mvmvif->phy_ctxt->color;
	else
		WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		if (vif->bss_conf.assoc)
			data->n_interfaces[id]++;
		break;
	case NL80211_IFTYPE_AP:
		if (mvmvif->ap_active)
			data->n_interfaces[id]++;
		break;
	case NL80211_IFTYPE_MONITOR:
		if (mvmvif->monitor_active)
			data->n_interfaces[id]++;
		break;
	case NL80211_IFTYPE_P2P_DEVICE:
		break;
	case NL80211_IFTYPE_ADHOC:
		if (vif->bss_conf.ibss_joined)
			data->n_interfaces[id]++;
		break;
	default:
		WARN_ON_ONCE(1);
		break;
	}
}
Beispiel #16
0
static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
					    struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	bool *global_bound = data;

	if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
		*global_bound = true;
}
Beispiel #17
0
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
		return -EINVAL;

	return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
}
Beispiel #18
0
static void iwl_mvm_power_iterator(void *_data, u8 *mac,
				   struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_power_vifs *power_iterator = _data;

	mvmvif->pm_enabled = false;
	switch (ieee80211_vif_type_p2p(vif)) {
	case NL80211_IFTYPE_P2P_DEVICE:
		break;

	case NL80211_IFTYPE_P2P_GO:
	case NL80211_IFTYPE_AP:
		/* only a single MAC of the same type */
		WARN_ON(power_iterator->ap_vif);
		power_iterator->ap_vif = vif;
		if (mvmvif->phy_ctxt)
			if (mvmvif->phy_ctxt->id < MAX_PHYS)
				power_iterator->ap_active = true;
		break;

	case NL80211_IFTYPE_MONITOR:
		/* only a single MAC of the same type */
		WARN_ON(power_iterator->monitor_vif);
		power_iterator->monitor_vif = vif;
		if (mvmvif->phy_ctxt)
			if (mvmvif->phy_ctxt->id < MAX_PHYS)
				power_iterator->monitor_active = true;
		break;

	case NL80211_IFTYPE_P2P_CLIENT:
		/* only a single MAC of the same type */
		WARN_ON(power_iterator->p2p_vif);
		power_iterator->p2p_vif = vif;
		if (mvmvif->phy_ctxt)
			if (mvmvif->phy_ctxt->id < MAX_PHYS)
				power_iterator->p2p_active = true;
		break;

	case NL80211_IFTYPE_STATION:
		/* only a single MAC of the same type */
		WARN_ON(power_iterator->bss_vif);
		power_iterator->bss_vif = vif;
		if (mvmvif->phy_ctxt)
			if (mvmvif->phy_ctxt->id < MAX_PHYS)
				power_iterator->bss_active = true;

		if (mvmvif->bf_data.bf_enabled &&
		    !WARN_ON(power_iterator->bf_vif))
			power_iterator->bf_vif = vif;

		break;

	default:
		break;
	}
}
Beispiel #19
0
static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
				struct iwl_powertable_cmd *cmd)
{
	struct ieee80211_hw *hw = mvm->hw;
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct ieee80211_chanctx_conf *chanctx_conf;
	struct ieee80211_channel *chan;
	int dtimper, dtimper_msec;
	int keep_alive;
	bool radar_detect = false;

	cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
							    mvmvif->color));
	cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);

	if ((!vif->bss_conf.ps) ||
	    (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM))
		return;

	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);

	dtimper = hw->conf.ps_dtim_period ?: 1;

	/* Check if radar detection is required on current channel */
	rcu_read_lock();
	chanctx_conf = rcu_dereference(vif->chanctx_conf);
	WARN_ON(!chanctx_conf);
	if (chanctx_conf) {
		chan = chanctx_conf->def.chan;
		radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
	}
	rcu_read_unlock();

	/* Check skip over DTIM conditions */
	if (!radar_detect && (dtimper <= 10) &&
	    (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) {
		cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK);
		cmd->num_skip_dtim = 2;
	}

	/* Check that keep alive period is at least 3 * DTIM */
	dtimper_msec = dtimper * vif->bss_conf.beacon_int;
	keep_alive = max_t(int, 3 * dtimper_msec,
			   MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC);
	keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);

	cmd->keep_alive_seconds = cpu_to_le16(keep_alive);

	if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) {
		/* TODO: Also for D3 (device sleep / WoWLAN) */
		cmd->rx_data_timeout = cpu_to_le32(10);
		cmd->tx_data_timeout = cpu_to_le32(10);
	} else {
		cmd->rx_data_timeout = cpu_to_le32(50);
		cmd->tx_data_timeout = cpu_to_le32(50);
	}
}
Beispiel #20
0
static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
				   struct ieee80211_vif *vif)
{
	struct iwl_mvm_quota_iterator_data *data = _data;
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	u16 id;

	/* skip disabled interfaces here immediately */
	if (vif == data->disabled_vif)
		return;

	if (!mvmvif->phy_ctxt)
		return;

	/* currently, PHY ID == binding ID */
	id = mvmvif->phy_ctxt->id;

	/* need at least one binding per PHY */
	BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);

	if (WARN_ON_ONCE(id >= MAX_BINDINGS))
		return;

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		if (vif->bss_conf.assoc)
			break;
		return;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_ADHOC:
		if (mvmvif->ap_ibss_active)
			break;
		return;
	case NL80211_IFTYPE_MONITOR:
		if (mvmvif->monitor_active)
			break;
		return;
	case NL80211_IFTYPE_P2P_DEVICE:
		return;
	default:
		WARN_ON_ONCE(1);
		return;
	}

	if (data->colors[id] < 0)
		data->colors[id] = mvmvif->phy_ctxt->color;
	else
		WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);

	data->n_interfaces[id]++;

	if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) {
		data->n_low_latency_bindings++;
		data->low_latency[id] = true;
	}
}
Beispiel #21
0
void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	debugfs_remove(mvmvif->dbgfs_slink);
	mvmvif->dbgfs_slink = NULL;

	debugfs_remove_recursive(mvmvif->dbgfs_dir);
	mvmvif->dbgfs_dir = NULL;
}
Beispiel #22
0
Datei: scan.c Projekt: 3bsa/linux
static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
					    struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	int *global_cnt = data;

	if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
	    mvmvif->phy_ctxt->id < MAX_PHYS)
		*global_cnt += 1;
}
Beispiel #23
0
int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
				 struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

	if (!mvmvif->bf_data.bf_enabled)
		return 0;

	return iwl_mvm_enable_beacon_filter(mvm, vif);
}
Beispiel #24
0
static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
        struct ieee80211_vif *vif)
{
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    bool *disable_ps = _data;

    if (mvmvif->phy_ctxt)
        if (mvmvif->phy_ctxt->id < MAX_PHYS)
            *disable_ps |= mvmvif->ps_disabled;
}
Beispiel #25
0
int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
                                   struct ieee80211_vif *vif,
                                   bool enable, u32 flags)
{
    int ret;
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    struct iwl_mac_power_cmd cmd = {};

    if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
        return 0;

    if (!vif->bss_conf.assoc)
        return 0;

    iwl_mvm_power_build_cmd(mvm, vif, &cmd);
    if (enable) {
        /* configure skip over dtim up to 306TU - 314 msec */
        int dtimper = vif->bss_conf.dtim_period ?: 1;
        int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
        bool radar_detect = iwl_mvm_power_is_radar(vif);

        if (WARN_ON(!dtimper_tu))
            return 0;

        /* Check skip over DTIM conditions */
        /* TODO: check that multicast wake lock is off */
        if (!radar_detect && (dtimper < 10)) {
            cmd.skip_dtim_periods = 306 / dtimper_tu;
            if (cmd.skip_dtim_periods)
                cmd.flags |= cpu_to_le16(
                                 POWER_FLAGS_SKIP_OVER_DTIM_MSK);
        }
    }
    iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
    memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd));
#endif
    ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags,
                               sizeof(cmd), &cmd);
    if (ret)
        return ret;

    /* configure beacon filtering */
    if (mvmvif != mvm->bf_allowed_vif)
        return 0;

    if (enable) {
        struct iwl_beacon_filter_cmd cmd_bf = {
            IWL_BF_CMD_CONFIG_D0I3,
            .bf_enable_beacon_filter = cpu_to_le32(1),
        };
        ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
                                            flags, true);
    } else {
        if (mvmvif->bf_data.bf_enabled)
Beispiel #26
0
static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      struct ieee80211_chanctx_conf *ctx)
{
    struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
    struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv;
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    int ret;

    mutex_lock(&mvm->mutex);

    mvmvif->phy_ctxt = phyctx;

    switch (vif->type) {
    case NL80211_IFTYPE_AP:
        /*
         * The AP binding flow is handled as part of the start_ap flow
         * (in bss_info_changed).
         */
        ret = 0;
        goto out_unlock;
    case NL80211_IFTYPE_STATION:
    case NL80211_IFTYPE_ADHOC:
    case NL80211_IFTYPE_MONITOR:
        break;
    default:
        ret = -EINVAL;
        goto out_unlock;
    }

    ret = iwl_mvm_binding_add_vif(mvm, vif);
    if (ret)
        goto out_unlock;

    /*
     * Setting the quota at this stage is only required for monitor
     * interfaces. For the other types, the bss_info changed flow
     * will handle quota settings.
     */
    if (vif->type == NL80211_IFTYPE_MONITOR) {
        ret = iwl_mvm_update_quotas(mvm, vif);
        if (ret)
            goto out_remove_binding;
    }

    goto out_unlock;

out_remove_binding:
    iwl_mvm_binding_remove_vif(mvm, vif);
out_unlock:
    mutex_unlock(&mvm->mutex);
    if (ret)
        mvmvif->phy_ctxt = NULL;
    return ret;
}
Beispiel #27
0
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta,
                                 enum ieee80211_sta_state old_state,
                                 enum ieee80211_sta_state new_state)
{
    struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    int ret;

    IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n",
                       sta->addr, old_state, new_state);

    /* this would be a mac80211 bug ... but don't crash */
    if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
        return -EINVAL;

    /* if a STA is being removed, reuse its ID */
    flush_work(&mvm->sta_drained_wk);

    mutex_lock(&mvm->mutex);
    if (old_state == IEEE80211_STA_NOTEXIST &&
            new_state == IEEE80211_STA_NONE) {
        ret = iwl_mvm_add_sta(mvm, vif, sta);
    } else if (old_state == IEEE80211_STA_NONE &&
               new_state == IEEE80211_STA_AUTH) {
        ret = 0;
    } else if (old_state == IEEE80211_STA_AUTH &&
               new_state == IEEE80211_STA_ASSOC) {
        ret = iwl_mvm_update_sta(mvm, vif, sta);
        if (ret == 0)
            iwl_mvm_rs_rate_init(mvm, sta,
                                 mvmvif->phy_ctxt->channel->band);
    } else if (old_state == IEEE80211_STA_ASSOC &&
               new_state == IEEE80211_STA_AUTHORIZED) {
        ret = 0;
    } else if (old_state == IEEE80211_STA_AUTHORIZED &&
               new_state == IEEE80211_STA_ASSOC) {
        ret = 0;
    } else if (old_state == IEEE80211_STA_ASSOC &&
               new_state == IEEE80211_STA_AUTH) {
        ret = 0;
    } else if (old_state == IEEE80211_STA_AUTH &&
               new_state == IEEE80211_STA_NONE) {
        ret = 0;
    } else if (old_state == IEEE80211_STA_NONE &&
               new_state == IEEE80211_STA_NOTEXIST) {
        ret = iwl_mvm_rm_sta(mvm, vif, sta);
    } else {
        ret = -EIO;
    }
    mutex_unlock(&mvm->mutex);

    return ret;
}
Beispiel #28
0
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
        struct ieee80211_vif *vif,
        struct ieee80211_bss_conf *bss_conf,
        u32 changes)
{
    struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    int ret;

    ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
    if (ret)
        IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);

    if (changes & BSS_CHANGED_ASSOC) {
        if (bss_conf->assoc) {
            /* add quota for this interface */
            ret = iwl_mvm_update_quotas(mvm, vif);
            if (ret) {
                IWL_ERR(mvm, "failed to update quotas\n");
                return;
            }
        } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
            /* remove AP station now that the MAC is unassoc */
            ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
            if (ret)
                IWL_ERR(mvm, "failed to remove AP station\n");
            mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
            /* remove quota for this interface */
            ret = iwl_mvm_update_quotas(mvm, NULL);
            if (ret)
                IWL_ERR(mvm, "failed to update quotas\n");
        }
    } else if (changes & BSS_CHANGED_DTIM_PERIOD) {
        /*
         * We received a beacon _after_ association so
         * remove the session protection.
         */
        iwl_mvm_remove_time_event(mvm, mvmvif,
                                  &mvmvif->time_event_data);
    } else if (changes & BSS_CHANGED_PS) {
        /*
         * TODO: remove this temporary code.
         * Currently MVM FW supports power management only on single
         * MAC. Avoid power mode update if more than one interface
         * is active.
         */
        IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
                           mvm->vif_count);
        if (mvm->vif_count == 1) {
            ret = iwl_mvm_power_update_mode(mvm, vif);
            if (ret)
                IWL_ERR(mvm, "failed to update power mode\n");
        }
    }
}
Beispiel #29
0
static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
			    struct sk_buff *skb,
			    struct iwl_rx_mpdu_desc *desc)
{
	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);

	if (mvmvif->features & NETIF_F_RXCSUM &&
	    desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_IP_HDR_CSUM_OK) &&
	    desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_TCP_UDP_CSUM_OK))
		skb->ip_summed = CHECKSUM_UNNECESSARY;
}
Beispiel #30
0
Datei: rx.c Projekt: mdamt/linux
static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
			    struct sk_buff *skb,
			    u32 status)
{
	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);

	if (mvmvif->features & NETIF_F_RXCSUM &&
	    status & RX_MPDU_RES_STATUS_CSUM_DONE &&
	    status & RX_MPDU_RES_STATUS_CSUM_OK)
		skb->ip_summed = CHECKSUM_UNNECESSARY;
}