wifi: ath12k: implement WoW enable and wakeup commands
Implement WoW enable and WoW wakeup commands which are needed for suspend/resume. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com> Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com> Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> Link: https://patch.msgid.link/20240604055407.12506-3-quic_bqiang@quicinc.com
This commit is contained in:
parent
3216b7bcd7
commit
5931741709
@ -26,6 +26,7 @@ ath12k-y += core.o \
|
|||||||
ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o
|
ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o
|
||||||
ath12k-$(CONFIG_ACPI) += acpi.o
|
ath12k-$(CONFIG_ACPI) += acpi.o
|
||||||
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
|
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
|
||||||
|
ath12k-$(CONFIG_PM) += wow.o
|
||||||
|
|
||||||
# for tracing framework to find trace.h
|
# for tracing framework to find trace.h
|
||||||
CFLAGS_trace.o := -I$(src)
|
CFLAGS_trace.o := -I$(src)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "hif.h"
|
#include "hif.h"
|
||||||
#include "fw.h"
|
#include "fw.h"
|
||||||
#include "debugfs.h"
|
#include "debugfs.h"
|
||||||
|
#include "wow.h"
|
||||||
|
|
||||||
unsigned int ath12k_debug_mask;
|
unsigned int ath12k_debug_mask;
|
||||||
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
|
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
|
||||||
@ -1285,6 +1286,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
|
|||||||
timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
|
timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
|
||||||
init_completion(&ab->htc_suspend);
|
init_completion(&ab->htc_suspend);
|
||||||
init_completion(&ab->restart_completed);
|
init_completion(&ab->restart_completed);
|
||||||
|
init_completion(&ab->wow.wakeup_completed);
|
||||||
|
|
||||||
ab->dev = dev;
|
ab->dev = dev;
|
||||||
ab->hif.bus = bus;
|
ab->hif.bus = bus;
|
||||||
|
@ -765,6 +765,10 @@ struct ath12k_base {
|
|||||||
const struct ath12k_hif_ops *ops;
|
const struct ath12k_hif_ops *ops;
|
||||||
} hif;
|
} hif;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct completion wakeup_completed;
|
||||||
|
} wow;
|
||||||
|
|
||||||
struct ath12k_ce ce;
|
struct ath12k_ce ce;
|
||||||
struct timer_list rx_replenish_retry;
|
struct timer_list rx_replenish_retry;
|
||||||
struct ath12k_hal hal;
|
struct ath12k_hal hal;
|
||||||
|
@ -7030,6 +7030,66 @@ exit:
|
|||||||
kfree(tb);
|
kfree(tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ath12k_wmi_wow_wakeup_host_parse(struct ath12k_base *ab,
|
||||||
|
u16 tag, u16 len,
|
||||||
|
const void *ptr, void *data)
|
||||||
|
{
|
||||||
|
const struct wmi_wow_ev_pg_fault_param *pf_param;
|
||||||
|
const struct wmi_wow_ev_param *param;
|
||||||
|
struct wmi_wow_ev_arg *arg = data;
|
||||||
|
int pf_len;
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case WMI_TAG_WOW_EVENT_INFO:
|
||||||
|
param = ptr;
|
||||||
|
arg->wake_reason = le32_to_cpu(param->wake_reason);
|
||||||
|
ath12k_dbg(ab, ATH12K_DBG_WMI, "wow wakeup host reason %d %s\n",
|
||||||
|
arg->wake_reason, wow_reason(arg->wake_reason));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMI_TAG_ARRAY_BYTE:
|
||||||
|
if (arg && arg->wake_reason == WOW_REASON_PAGE_FAULT) {
|
||||||
|
pf_param = ptr;
|
||||||
|
pf_len = le32_to_cpu(pf_param->len);
|
||||||
|
if (pf_len > len - sizeof(pf_len) ||
|
||||||
|
pf_len < 0) {
|
||||||
|
ath12k_warn(ab, "invalid wo reason page fault buffer len %d\n",
|
||||||
|
pf_len);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
ath12k_dbg(ab, ATH12K_DBG_WMI, "wow_reason_page_fault len %d\n",
|
||||||
|
pf_len);
|
||||||
|
ath12k_dbg_dump(ab, ATH12K_DBG_WMI,
|
||||||
|
"wow_reason_page_fault packet present",
|
||||||
|
"wow_pg_fault ",
|
||||||
|
pf_param->data,
|
||||||
|
pf_len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath12k_wmi_event_wow_wakeup_host(struct ath12k_base *ab, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct wmi_wow_ev_arg arg = { };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,
|
||||||
|
ath12k_wmi_wow_wakeup_host_parse,
|
||||||
|
&arg);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_warn(ab, "failed to parse wmi wow wakeup host event tlv: %d\n",
|
||||||
|
ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
complete(&ab->wow.wakeup_completed);
|
||||||
|
}
|
||||||
|
|
||||||
static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
|
static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct wmi_cmd_hdr *cmd_hdr;
|
struct wmi_cmd_hdr *cmd_hdr;
|
||||||
@ -7150,6 +7210,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
|
|||||||
case WMI_DIAG_EVENTID:
|
case WMI_DIAG_EVENTID:
|
||||||
ath12k_wmi_diag_event(ab, skb);
|
ath12k_wmi_diag_event(ab, skb);
|
||||||
break;
|
break;
|
||||||
|
case WMI_WOW_WAKEUP_HOST_EVENTID:
|
||||||
|
ath12k_wmi_event_wow_wakeup_host(ab, skb);
|
||||||
|
break;
|
||||||
/* TODO: Add remaining events */
|
/* TODO: Add remaining events */
|
||||||
default:
|
default:
|
||||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
|
ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
|
||||||
@ -7359,3 +7422,45 @@ void ath12k_wmi_detach(struct ath12k_base *ab)
|
|||||||
|
|
||||||
ath12k_wmi_free_dbring_caps(ab);
|
ath12k_wmi_free_dbring_caps(ab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath12k_wmi_wow_host_wakeup_ind(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
struct wmi_wow_host_wakeup_cmd *cmd;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = sizeof(*cmd);
|
||||||
|
skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = (struct wmi_wow_host_wakeup_cmd *)skb->data;
|
||||||
|
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_HOSTWAKEUP_FROM_SLEEP_CMD,
|
||||||
|
sizeof(*cmd));
|
||||||
|
|
||||||
|
ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow host wakeup ind\n");
|
||||||
|
|
||||||
|
return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath12k_wmi_wow_enable(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
struct wmi_wow_enable_cmd *cmd;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = sizeof(*cmd);
|
||||||
|
skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = (struct wmi_wow_enable_cmd *)skb->data;
|
||||||
|
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_WOW_ENABLE_CMD,
|
||||||
|
sizeof(*cmd));
|
||||||
|
|
||||||
|
cmd->enable = cpu_to_le32(1);
|
||||||
|
cmd->pause_iface_config = cpu_to_le32(WOW_IFACE_PAUSE_ENABLED);
|
||||||
|
ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi tlv wow enable\n");
|
||||||
|
|
||||||
|
return ath12k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID);
|
||||||
|
}
|
||||||
|
@ -4902,6 +4902,178 @@ struct wmi_twt_disable_event {
|
|||||||
__le32 status;
|
__le32 status;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* WOW structures */
|
||||||
|
enum wmi_wow_wakeup_event {
|
||||||
|
WOW_BMISS_EVENT = 0,
|
||||||
|
WOW_BETTER_AP_EVENT,
|
||||||
|
WOW_DEAUTH_RECVD_EVENT,
|
||||||
|
WOW_MAGIC_PKT_RECVD_EVENT,
|
||||||
|
WOW_GTK_ERR_EVENT,
|
||||||
|
WOW_FOURWAY_HSHAKE_EVENT,
|
||||||
|
WOW_EAPOL_RECVD_EVENT,
|
||||||
|
WOW_NLO_DETECTED_EVENT,
|
||||||
|
WOW_DISASSOC_RECVD_EVENT,
|
||||||
|
WOW_PATTERN_MATCH_EVENT,
|
||||||
|
WOW_CSA_IE_EVENT,
|
||||||
|
WOW_PROBE_REQ_WPS_IE_EVENT,
|
||||||
|
WOW_AUTH_REQ_EVENT,
|
||||||
|
WOW_ASSOC_REQ_EVENT,
|
||||||
|
WOW_HTT_EVENT,
|
||||||
|
WOW_RA_MATCH_EVENT,
|
||||||
|
WOW_HOST_AUTO_SHUTDOWN_EVENT,
|
||||||
|
WOW_IOAC_MAGIC_EVENT,
|
||||||
|
WOW_IOAC_SHORT_EVENT,
|
||||||
|
WOW_IOAC_EXTEND_EVENT,
|
||||||
|
WOW_IOAC_TIMER_EVENT,
|
||||||
|
WOW_DFS_PHYERR_RADAR_EVENT,
|
||||||
|
WOW_BEACON_EVENT,
|
||||||
|
WOW_CLIENT_KICKOUT_EVENT,
|
||||||
|
WOW_EVENT_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_wow_interface_cfg {
|
||||||
|
WOW_IFACE_PAUSE_ENABLED,
|
||||||
|
WOW_IFACE_PAUSE_DISABLED
|
||||||
|
};
|
||||||
|
|
||||||
|
#define C2S(x) case x: return #x
|
||||||
|
|
||||||
|
static inline const char *wow_wakeup_event(enum wmi_wow_wakeup_event ev)
|
||||||
|
{
|
||||||
|
switch (ev) {
|
||||||
|
C2S(WOW_BMISS_EVENT);
|
||||||
|
C2S(WOW_BETTER_AP_EVENT);
|
||||||
|
C2S(WOW_DEAUTH_RECVD_EVENT);
|
||||||
|
C2S(WOW_MAGIC_PKT_RECVD_EVENT);
|
||||||
|
C2S(WOW_GTK_ERR_EVENT);
|
||||||
|
C2S(WOW_FOURWAY_HSHAKE_EVENT);
|
||||||
|
C2S(WOW_EAPOL_RECVD_EVENT);
|
||||||
|
C2S(WOW_NLO_DETECTED_EVENT);
|
||||||
|
C2S(WOW_DISASSOC_RECVD_EVENT);
|
||||||
|
C2S(WOW_PATTERN_MATCH_EVENT);
|
||||||
|
C2S(WOW_CSA_IE_EVENT);
|
||||||
|
C2S(WOW_PROBE_REQ_WPS_IE_EVENT);
|
||||||
|
C2S(WOW_AUTH_REQ_EVENT);
|
||||||
|
C2S(WOW_ASSOC_REQ_EVENT);
|
||||||
|
C2S(WOW_HTT_EVENT);
|
||||||
|
C2S(WOW_RA_MATCH_EVENT);
|
||||||
|
C2S(WOW_HOST_AUTO_SHUTDOWN_EVENT);
|
||||||
|
C2S(WOW_IOAC_MAGIC_EVENT);
|
||||||
|
C2S(WOW_IOAC_SHORT_EVENT);
|
||||||
|
C2S(WOW_IOAC_EXTEND_EVENT);
|
||||||
|
C2S(WOW_IOAC_TIMER_EVENT);
|
||||||
|
C2S(WOW_DFS_PHYERR_RADAR_EVENT);
|
||||||
|
C2S(WOW_BEACON_EVENT);
|
||||||
|
C2S(WOW_CLIENT_KICKOUT_EVENT);
|
||||||
|
C2S(WOW_EVENT_MAX);
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum wmi_wow_wake_reason {
|
||||||
|
WOW_REASON_UNSPECIFIED = -1,
|
||||||
|
WOW_REASON_NLOD = 0,
|
||||||
|
WOW_REASON_AP_ASSOC_LOST,
|
||||||
|
WOW_REASON_LOW_RSSI,
|
||||||
|
WOW_REASON_DEAUTH_RECVD,
|
||||||
|
WOW_REASON_DISASSOC_RECVD,
|
||||||
|
WOW_REASON_GTK_HS_ERR,
|
||||||
|
WOW_REASON_EAP_REQ,
|
||||||
|
WOW_REASON_FOURWAY_HS_RECV,
|
||||||
|
WOW_REASON_TIMER_INTR_RECV,
|
||||||
|
WOW_REASON_PATTERN_MATCH_FOUND,
|
||||||
|
WOW_REASON_RECV_MAGIC_PATTERN,
|
||||||
|
WOW_REASON_P2P_DISC,
|
||||||
|
WOW_REASON_WLAN_HB,
|
||||||
|
WOW_REASON_CSA_EVENT,
|
||||||
|
WOW_REASON_PROBE_REQ_WPS_IE_RECV,
|
||||||
|
WOW_REASON_AUTH_REQ_RECV,
|
||||||
|
WOW_REASON_ASSOC_REQ_RECV,
|
||||||
|
WOW_REASON_HTT_EVENT,
|
||||||
|
WOW_REASON_RA_MATCH,
|
||||||
|
WOW_REASON_HOST_AUTO_SHUTDOWN,
|
||||||
|
WOW_REASON_IOAC_MAGIC_EVENT,
|
||||||
|
WOW_REASON_IOAC_SHORT_EVENT,
|
||||||
|
WOW_REASON_IOAC_EXTEND_EVENT,
|
||||||
|
WOW_REASON_IOAC_TIMER_EVENT,
|
||||||
|
WOW_REASON_ROAM_HO,
|
||||||
|
WOW_REASON_DFS_PHYERR_RADADR_EVENT,
|
||||||
|
WOW_REASON_BEACON_RECV,
|
||||||
|
WOW_REASON_CLIENT_KICKOUT_EVENT,
|
||||||
|
WOW_REASON_PAGE_FAULT = 0x3a,
|
||||||
|
WOW_REASON_DEBUG_TEST = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const char *wow_reason(enum wmi_wow_wake_reason reason)
|
||||||
|
{
|
||||||
|
switch (reason) {
|
||||||
|
C2S(WOW_REASON_UNSPECIFIED);
|
||||||
|
C2S(WOW_REASON_NLOD);
|
||||||
|
C2S(WOW_REASON_AP_ASSOC_LOST);
|
||||||
|
C2S(WOW_REASON_LOW_RSSI);
|
||||||
|
C2S(WOW_REASON_DEAUTH_RECVD);
|
||||||
|
C2S(WOW_REASON_DISASSOC_RECVD);
|
||||||
|
C2S(WOW_REASON_GTK_HS_ERR);
|
||||||
|
C2S(WOW_REASON_EAP_REQ);
|
||||||
|
C2S(WOW_REASON_FOURWAY_HS_RECV);
|
||||||
|
C2S(WOW_REASON_TIMER_INTR_RECV);
|
||||||
|
C2S(WOW_REASON_PATTERN_MATCH_FOUND);
|
||||||
|
C2S(WOW_REASON_RECV_MAGIC_PATTERN);
|
||||||
|
C2S(WOW_REASON_P2P_DISC);
|
||||||
|
C2S(WOW_REASON_WLAN_HB);
|
||||||
|
C2S(WOW_REASON_CSA_EVENT);
|
||||||
|
C2S(WOW_REASON_PROBE_REQ_WPS_IE_RECV);
|
||||||
|
C2S(WOW_REASON_AUTH_REQ_RECV);
|
||||||
|
C2S(WOW_REASON_ASSOC_REQ_RECV);
|
||||||
|
C2S(WOW_REASON_HTT_EVENT);
|
||||||
|
C2S(WOW_REASON_RA_MATCH);
|
||||||
|
C2S(WOW_REASON_HOST_AUTO_SHUTDOWN);
|
||||||
|
C2S(WOW_REASON_IOAC_MAGIC_EVENT);
|
||||||
|
C2S(WOW_REASON_IOAC_SHORT_EVENT);
|
||||||
|
C2S(WOW_REASON_IOAC_EXTEND_EVENT);
|
||||||
|
C2S(WOW_REASON_IOAC_TIMER_EVENT);
|
||||||
|
C2S(WOW_REASON_ROAM_HO);
|
||||||
|
C2S(WOW_REASON_DFS_PHYERR_RADADR_EVENT);
|
||||||
|
C2S(WOW_REASON_BEACON_RECV);
|
||||||
|
C2S(WOW_REASON_CLIENT_KICKOUT_EVENT);
|
||||||
|
C2S(WOW_REASON_PAGE_FAULT);
|
||||||
|
C2S(WOW_REASON_DEBUG_TEST);
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef C2S
|
||||||
|
|
||||||
|
struct wmi_wow_enable_cmd {
|
||||||
|
__le32 tlv_header;
|
||||||
|
__le32 enable;
|
||||||
|
__le32 pause_iface_config;
|
||||||
|
__le32 flags;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_wow_host_wakeup_cmd {
|
||||||
|
__le32 tlv_header;
|
||||||
|
__le32 reserved;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_wow_ev_param {
|
||||||
|
__le32 vdev_id;
|
||||||
|
__le32 flag;
|
||||||
|
__le32 wake_reason;
|
||||||
|
__le32 data_len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_wow_ev_pg_fault_param {
|
||||||
|
__le32 len;
|
||||||
|
u8 data[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_wow_ev_arg {
|
||||||
|
enum wmi_wow_wake_reason wake_reason;
|
||||||
|
};
|
||||||
|
|
||||||
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
|
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
|
||||||
struct ath12k_wmi_resource_config_arg *config);
|
struct ath12k_wmi_resource_config_arg *config);
|
||||||
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
|
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
|
||||||
@ -5054,4 +5226,6 @@ ath12k_wmi_mac_phy_get_hw_link_id(const struct ath12k_wmi_mac_phy_caps_params *p
|
|||||||
WMI_CAPS_PARAMS_HW_LINK_ID);
|
WMI_CAPS_PARAMS_HW_LINK_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath12k_wmi_wow_host_wakeup_ind(struct ath12k *ar);
|
||||||
|
int ath12k_wmi_wow_enable(struct ath12k *ar);
|
||||||
#endif
|
#endif
|
||||||
|
79
drivers/net/wireless/ath/ath12k/wow.c
Normal file
79
drivers/net/wireless/ath/ath12k/wow.c
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include "mac.h"
|
||||||
|
#include "core.h"
|
||||||
|
#include "hif.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "wmi.h"
|
||||||
|
#include "wow.h"
|
||||||
|
|
||||||
|
int ath12k_wow_enable(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
struct ath12k_base *ab = ar->ab;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
clear_bit(ATH12K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
|
||||||
|
|
||||||
|
/* The firmware might be busy and it can not enter WoW immediately.
|
||||||
|
* In that case firmware notifies host with
|
||||||
|
* ATH12K_HTC_MSG_NACK_SUSPEND message, asking host to try again
|
||||||
|
* later. Per the firmware team there could be up to 10 loops.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ATH12K_WOW_RETRY_NUM; i++) {
|
||||||
|
reinit_completion(&ab->htc_suspend);
|
||||||
|
|
||||||
|
ret = ath12k_wmi_wow_enable(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_warn(ab, "failed to issue wow enable: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);
|
||||||
|
if (ret == 0) {
|
||||||
|
ath12k_warn(ab,
|
||||||
|
"timed out while waiting for htc suspend completion\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_bit(ATH12K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags))
|
||||||
|
/* success, suspend complete received */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ath12k_warn(ab, "htc suspend not complete, retrying (try %d)\n",
|
||||||
|
i);
|
||||||
|
msleep(ATH12K_WOW_RETRY_WAIT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ath12k_warn(ab, "htc suspend not complete, failing after %d tries\n", i);
|
||||||
|
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath12k_wow_wakeup(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
struct ath12k_base *ab = ar->ab;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
reinit_completion(&ab->wow.wakeup_completed);
|
||||||
|
|
||||||
|
ret = ath12k_wmi_wow_host_wakeup_ind(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_warn(ab, "failed to send wow wakeup indication: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
|
||||||
|
if (ret == 0) {
|
||||||
|
ath12k_warn(ab, "timed out while waiting for wow wakeup completion\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
30
drivers/net/wireless/ath/ath12k/wow.h
Normal file
30
drivers/net/wireless/ath/ath12k/wow.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ATH12K_WOW_H
|
||||||
|
#define ATH12K_WOW_H
|
||||||
|
|
||||||
|
#define ATH12K_WOW_RETRY_NUM 10
|
||||||
|
#define ATH12K_WOW_RETRY_WAIT_MS 200
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
|
int ath12k_wow_enable(struct ath12k *ar);
|
||||||
|
int ath12k_wow_wakeup(struct ath12k *ar);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int ath12k_wow_enable(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ath12k_wow_wakeup(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_PM */
|
||||||
|
#endif /* ATH12K_WOW_H */
|
Loading…
Reference in New Issue
Block a user