Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76015021 authored by John W. Linville's avatar John W. Linville
Browse files
parents f7a01cac fded313e
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -430,7 +430,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
		    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
		    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);


	iwl_trans_d3_suspend(priv->trans);
	iwl_trans_d3_suspend(priv->trans, false);


	goto out;
	goto out;


@@ -504,7 +504,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
	/* we'll clear ctx->vif during iwlagn_prepare_restart() */
	/* we'll clear ctx->vif during iwlagn_prepare_restart() */
	vif = ctx->vif;
	vif = ctx->vif;


	ret = iwl_trans_d3_resume(priv->trans, &d3_status);
	ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
	if (ret)
	if (ret)
		goto out_unlock;
		goto out_unlock;


+8 −6
Original line number Original line Diff line number Diff line
@@ -428,8 +428,9 @@ struct iwl_trans_ops {
	void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
	void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
	void (*stop_device)(struct iwl_trans *trans);
	void (*stop_device)(struct iwl_trans *trans);


	void (*d3_suspend)(struct iwl_trans *trans);
	void (*d3_suspend)(struct iwl_trans *trans, bool test);
	int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
	int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
			 bool test);


	int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
	int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);


@@ -588,17 +589,18 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
	trans->state = IWL_TRANS_NO_FW;
	trans->state = IWL_TRANS_NO_FW;
}
}


static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
{
{
	might_sleep();
	might_sleep();
	trans->ops->d3_suspend(trans);
	trans->ops->d3_suspend(trans, test);
}
}


static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
				      enum iwl_d3_status *status)
				      enum iwl_d3_status *status,
				      bool test)
{
{
	might_sleep();
	might_sleep();
	return trans->ops->d3_resume(trans, status);
	return trans->ops->d3_resume(trans, status, test);
}
}


static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
+1 −1
Original line number Original line Diff line number Diff line
@@ -174,7 +174,7 @@ static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xaeaaaaaa),
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xaaaaaaaa),
	cpu_to_le32(0xcc00ff28),
	cpu_to_le32(0xcc00ff28),
	cpu_to_le32(0x0000aaaa),
	cpu_to_le32(0x0000aaaa),
+139 −10
Original line number Original line Diff line number Diff line
@@ -63,6 +63,7 @@


#include <linux/etherdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/ip.h>
#include <linux/fs.h>
#include <net/cfg80211.h>
#include <net/cfg80211.h>
#include <net/ipv6.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include <net/tcp.h>
@@ -756,7 +757,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
	return 0;
	return 0;
}
}


int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
			     struct cfg80211_wowlan *wowlan,
			     bool test)
{
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_d3_iter_data suspend_iter_data = {
	struct iwl_d3_iter_data suspend_iter_data = {
@@ -769,7 +772,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
	struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
	struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
	struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
	struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
	struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
	struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
	struct iwl_d3_manager_config d3_cfg_cmd = {
	struct iwl_d3_manager_config d3_cfg_cmd_data = {
		/*
		/*
		 * Program the minimum sleep time to 10 seconds, as many
		 * Program the minimum sleep time to 10 seconds, as many
		 * platforms have issues processing a wakeup signal while
		 * platforms have issues processing a wakeup signal while
@@ -777,17 +780,30 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
		 */
		 */
		.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
		.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
	};
	};
	struct iwl_host_cmd d3_cfg_cmd = {
		.id = D3_CONFIG_CMD,
		.flags = CMD_SYNC | CMD_WANT_SKB,
		.data[0] = &d3_cfg_cmd_data,
		.len[0] = sizeof(d3_cfg_cmd_data),
	};
	struct wowlan_key_data key_data = {
	struct wowlan_key_data key_data = {
		.use_rsc_tsc = false,
		.use_rsc_tsc = false,
		.tkip = &tkip_cmd,
		.tkip = &tkip_cmd,
		.use_tkip = false,
		.use_tkip = false,
	};
	};
	int ret, i;
	int ret, i;
	int len __maybe_unused;
	u16 seq;
	u16 seq;
	u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
	u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;


	if (WARN_ON(!wowlan))
	if (!wowlan) {
		/*
		 * mac80211 shouldn't get here, but for D3 test
		 * it doesn't warrant a warning
		 */
		WARN_ON(!test);
		return -EINVAL;
		return -EINVAL;
	}


	key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
	key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
	if (!key_data.rsc_tsc)
	if (!key_data.rsc_tsc)
@@ -1012,14 +1028,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
		goto out;
		goto out;


	/* must be last -- this switches firmware state */
	/* must be last -- this switches firmware state */
	ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
	ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
				   sizeof(d3_cfg_cmd), &d3_cfg_cmd);
	if (ret)
	if (ret)
		goto out;
		goto out;
#ifdef CONFIG_IWLWIFI_DEBUGFS
	len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) &
		FH_RSCSR_FRAME_SIZE_MSK;
	if (len >= sizeof(u32) * 2) {
		mvm->d3_test_pme_ptr =
			le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
	} else if (test) {
		/* in test mode we require the pointer */
		ret = -EIO;
		goto out;
	}
#endif
	iwl_free_resp(&d3_cfg_cmd);


	clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
	clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);


	iwl_trans_d3_suspend(mvm->trans);
	iwl_trans_d3_suspend(mvm->trans, test);
 out:
 out:
	mvm->aux_sta.sta_id = old_aux_sta_id;
	mvm->aux_sta.sta_id = old_aux_sta_id;
	mvm_ap_sta->sta_id = old_ap_sta_id;
	mvm_ap_sta->sta_id = old_ap_sta_id;
@@ -1034,6 +1062,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
	return ret;
	return ret;
}
}


int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{
	return __iwl_mvm_suspend(hw, wowlan, false);
}

static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
					 struct ieee80211_vif *vif)
					 struct ieee80211_vif *vif)
{
{
@@ -1238,9 +1271,8 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
#endif
#endif
}
}


int iwl_mvm_resume(struct ieee80211_hw *hw)
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
{
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_d3_iter_data resume_iter_data = {
	struct iwl_d3_iter_data resume_iter_data = {
		.mvm = mvm,
		.mvm = mvm,
	};
	};
@@ -1260,7 +1292,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)


	vif = resume_iter_data.vif;
	vif = resume_iter_data.vif;


	ret = iwl_trans_d3_resume(mvm->trans, &d3_status);
	ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
	if (ret)
	if (ret)
		goto out_unlock;
		goto out_unlock;


@@ -1277,7 +1309,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
 out_unlock:
 out_unlock:
	mutex_unlock(&mvm->mutex);
	mutex_unlock(&mvm->mutex);


	if (vif)
	if (!test && vif)
		ieee80211_resume_disconnect(vif);
		ieee80211_resume_disconnect(vif);


	/* return 1 to reconfigure the device */
	/* return 1 to reconfigure the device */
@@ -1285,9 +1317,106 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
	return 1;
	return 1;
}
}


int iwl_mvm_resume(struct ieee80211_hw *hw)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);

	return __iwl_mvm_resume(mvm, false);
}

void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);


	device_set_wakeup_enable(mvm->trans->dev, enabled);
	device_set_wakeup_enable(mvm->trans->dev, enabled);
}
}

#ifdef CONFIG_IWLWIFI_DEBUGFS
static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
{
	struct iwl_mvm *mvm = inode->i_private;
	int err;

	if (mvm->d3_test_active)
		return -EBUSY;

	file->private_data = inode->i_private;

	ieee80211_stop_queues(mvm->hw);
	synchronize_net();

	/* start pseudo D3 */
	rtnl_lock();
	err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
	rtnl_unlock();
	if (err > 0)
		err = -EINVAL;
	if (err) {
		ieee80211_wake_queues(mvm->hw);
		return err;
	}
	mvm->d3_test_active = true;
	return 0;
}

static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
				    size_t count, loff_t *ppos)
{
	struct iwl_mvm *mvm = file->private_data;
	u32 pme_asserted;

	while (true) {
		pme_asserted = iwl_trans_read_mem32(mvm->trans,
						    mvm->d3_test_pme_ptr);
		if (pme_asserted)
			break;
		if (msleep_interruptible(100))
			break;
	}

	return 0;
}

static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
					      struct ieee80211_vif *vif)
{
	if (vif->type == NL80211_IFTYPE_STATION)
		ieee80211_connection_loss(vif);
}

static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
{
	struct iwl_mvm *mvm = inode->i_private;
	int remaining_time = 10;

	mvm->d3_test_active = false;
	__iwl_mvm_resume(mvm, true);
	iwl_abort_notification_waits(&mvm->notif_wait);
	ieee80211_restart_hw(mvm->hw);

	/* wait for restart and disconnect all interfaces */
	while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
	       remaining_time > 0) {
		remaining_time--;
		msleep(1000);
	}

	if (remaining_time == 0)
		IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n");

	ieee80211_iterate_active_interfaces_atomic(
		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
		iwl_mvm_d3_test_disconn_work_iter, NULL);

	ieee80211_wake_queues(mvm->hw);

	return 0;
}

const struct file_operations iwl_dbgfs_d3_test_ops = {
	.llseek = no_llseek,
	.open = iwl_mvm_d3_test_open,
	.read = iwl_mvm_d3_test_read,
	.release = iwl_mvm_d3_test_release,
};
#endif
+1 −0
Original line number Original line Diff line number Diff line
@@ -938,6 +938,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
	MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
	MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM_SLEEP
	MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
	MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
	MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
#endif
#endif


	/*
	/*
Loading