Commit ba9177fc authored by Carl Huang's avatar Carl Huang Committed by Kalle Valo
Browse files

ath11k: Add basic WoW functionalities



Implement basic WoW functionalities such as magic-packet, disconnect
and pattern. The logic is very similar to ath10k.

When WoW is configured, ath11k_core_suspend and ath11k_core_resume
are skipped as WoW configuration and hif suspend/resume are done in
ath11k_wow_op_suspend() and ath11k_wow_op_resume().

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

Signed-off-by: default avatarCarl Huang <quic_cjhuang@quicinc.com>
Signed-off-by: default avatarBaochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: default avatarWen Gong <quic_wgong@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/1644308006-22784-2-git-send-email-quic_cjhuang@quicinc.com
parent de29aff9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -16,14 +16,14 @@ ath11k-y += core.o \
	    ce.o \
	    peer.o \
	    dbring.o \
	    hw.o \
	    wow.o
	    hw.o

ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
ath11k-$(CONFIG_THERMAL) += thermal.o
ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o
ath11k-$(CONFIG_PM) += wow.o

obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o
ath11k_ahb-y += ahb.o
+33 −0
Original line number Diff line number Diff line
@@ -428,13 +428,30 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
	},
};

static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab)
{
	WARN_ON(!ab->hw_params.single_pdev_only);

	return &ab->pdevs[0];
}

int ath11k_core_suspend(struct ath11k_base *ab)
{
	int ret;
	struct ath11k_pdev *pdev;
	struct ath11k *ar;

	if (!ab->hw_params.supports_suspend)
		return -EOPNOTSUPP;

	/* so far single_pdev_only chips have supports_suspend as true
	 * and only the first pdev is valid.
	 */
	pdev = ath11k_core_get_single_pdev(ab);
	ar = pdev->ar;
	if (!ar || ar->state != ATH11K_STATE_OFF)
		return 0;

	/* TODO: there can frames in queues so for now add delay as a hack.
	 * Need to implement to handle and remove this delay.
	 */
@@ -447,6 +464,12 @@ int ath11k_core_suspend(struct ath11k_base *ab)
		return ret;
	}

	ret = ath11k_mac_wait_tx_complete(ar);
	if (ret) {
		ath11k_warn(ab, "failed to wait tx complete: %d\n", ret);
		return ret;
	}

	ret = ath11k_wow_enable(ab);
	if (ret) {
		ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret);
@@ -479,10 +502,20 @@ EXPORT_SYMBOL(ath11k_core_suspend);
int ath11k_core_resume(struct ath11k_base *ab)
{
	int ret;
	struct ath11k_pdev *pdev;
	struct ath11k *ar;

	if (!ab->hw_params.supports_suspend)
		return -EOPNOTSUPP;

	/* so far signle_pdev_only chips have supports_suspend as true
	 * and only the first pdev is valid.
	 */
	pdev = ath11k_core_get_single_pdev(ab);
	ar = pdev->ar;
	if (!ar || ar->state != ATH11K_STATE_OFF)
		return 0;

	ret = ath11k_hif_resume(ab);
	if (ret) {
		ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret);
+4 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include "thermal.h"
#include "dbring.h"
#include "spectral.h"
#include "wow.h"

#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)

@@ -590,6 +591,9 @@ struct ath11k {
	struct work_struct wmi_mgmt_tx_work;
	struct sk_buff_head wmi_mgmt_tx_queue;

	struct ath11k_wow wow;
	struct completion target_suspend;
	bool target_suspend_ack;
	struct ath11k_per_peer_tx_stats peer_tx_stats;
	struct list_head ppdu_stats_info;
	u32 ppdu_stat_list_depth;
+6 −0
Original line number Diff line number Diff line
@@ -272,6 +272,11 @@ void ath11k_htc_tx_completion_handler(struct ath11k_base *ab,
	ep_tx_complete(htc->ab, skb);
}

static void ath11k_htc_wakeup_from_suspend(struct ath11k_base *ab)
{
	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot wakeup from suspend is received\n");
}

void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
				      struct sk_buff *skb)
{
@@ -376,6 +381,7 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
			ath11k_htc_suspend_complete(ab, false);
			break;
		case ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID:
			ath11k_htc_wakeup_from_suspend(ab);
			break;
		default:
			ath11k_warn(ab, "ignoring unsolicited htc ep0 event %ld\n",
+45 −14
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
#include "testmode.h"
#include "peer.h"
#include "debugfs_sta.h"
#include "hif.h"
#include "wow.h"

#define CHAN2G(_channel, _freq, _flags) { \
	.band                   = NL80211_BAND_2GHZ, \
@@ -7258,31 +7260,47 @@ static int ath11k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
	return -EOPNOTSUPP;
}

static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
				u32 queues, bool drop)
static int ath11k_mac_flush_tx_complete(struct ath11k *ar)
{
	struct ath11k *ar = hw->priv;
	long time_left;

	if (drop)
		return;
	int ret = 0;

	time_left = wait_event_timeout(ar->dp.tx_empty_waitq,
				       (atomic_read(&ar->dp.num_tx_pending) == 0),
				       ATH11K_FLUSH_TIMEOUT);
	if (time_left == 0)
		ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
	if (time_left == 0) {
		ath11k_warn(ar->ab, "failed to flush transmit queue, data pkts pending %d\n",
			    atomic_read(&ar->dp.num_tx_pending));
		ret = -ETIMEDOUT;
	}

	time_left = wait_event_timeout(ar->txmgmt_empty_waitq,
				       (atomic_read(&ar->num_pending_mgmt_tx) == 0),
				       ATH11K_FLUSH_TIMEOUT);
	if (time_left == 0)
		ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n",
			    time_left);

	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
		   "mac mgmt tx flush mgmt pending %d\n",
	if (time_left == 0) {
		ath11k_warn(ar->ab, "failed to flush mgmt transmit queue, mgmt pkts pending %d\n",
			    atomic_read(&ar->num_pending_mgmt_tx));
		ret = -ETIMEDOUT;
	}

	return ret;
}

int ath11k_mac_wait_tx_complete(struct ath11k *ar)
{
	ath11k_mac_drain_tx(ar);
	return ath11k_mac_flush_tx_complete(ar);
}

static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
				u32 queues, bool drop)
{
	struct ath11k *ar = hw->priv;

	if (drop)
		return;

	ath11k_mac_flush_tx_complete(ar);
}

static int
@@ -8104,6 +8122,13 @@ static const struct ieee80211_ops ath11k_ops = {
	.flush				= ath11k_mac_op_flush,
	.sta_statistics			= ath11k_mac_op_sta_statistics,
	CFG80211_TESTMODE_CMD(ath11k_tm_cmd)

#ifdef CONFIG_PM
	.suspend			= ath11k_wow_op_suspend,
	.resume				= ath11k_wow_op_resume,
	.set_wakeup			= ath11k_wow_op_set_wakeup,
#endif

#ifdef CONFIG_ATH11K_DEBUGFS
	.sta_add_debugfs		= ath11k_debugfs_sta_op_add,
#endif
@@ -8473,6 +8498,12 @@ static int __ath11k_mac_register(struct ath11k *ar)
			NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
	}

	ret = ath11k_wow_init(ar);
	if (ret) {
		ath11k_warn(ar->ab, "failed to init wow: %d\n", ret);
		goto err_free_if_combs;
	}

	ar->hw->queues = ATH11K_HW_MAX_QUEUES;
	ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN;
	ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;
Loading