mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Previously commit 166a490f59
("wifi: ath11k: support hibernation") was
reverted due to [1], so currently we only support WoWLAN mode suspend.
This works well in scenarios where WLAN power is sustained during suspend,
however breaks in those where power is cut off.
This change basically brings the reverted commit back, but differs in that
we decide based on the PM policy to choose WoWLAN mode suspend or the
non-WoWLAN mode. As stated in the previous patch for now the PM policy is
determined based on machine models. That said we will choose WoWLAN mode
suspend if we are running on machines listed in ath11k_pm_quirk_table,
otherwise we choose the other one.
[1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Tested-by: Muhammad Usama Anjum <usama.anjum@collabora.com>
Tested-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Link: https://patch.msgid.link/20250328-ath11k-bring-hibernation-back-v3-4-23405ae23431@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
162 lines
4.2 KiB
C
162 lines
4.2 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
|
/*
|
|
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#ifndef _HIF_H_
|
|
#define _HIF_H_
|
|
|
|
#include "core.h"
|
|
|
|
struct ath11k_hif_ops {
|
|
u32 (*read32)(struct ath11k_base *ab, u32 address);
|
|
void (*write32)(struct ath11k_base *ab, u32 address, u32 data);
|
|
int (*read)(struct ath11k_base *ab, void *buf, u32 start, u32 end);
|
|
void (*irq_enable)(struct ath11k_base *ab);
|
|
void (*irq_disable)(struct ath11k_base *ab);
|
|
int (*start)(struct ath11k_base *ab);
|
|
void (*stop)(struct ath11k_base *ab);
|
|
int (*power_up)(struct ath11k_base *ab);
|
|
void (*power_down)(struct ath11k_base *ab, bool is_suspend);
|
|
int (*suspend)(struct ath11k_base *ab);
|
|
int (*resume)(struct ath11k_base *ab);
|
|
int (*map_service_to_pipe)(struct ath11k_base *ab, u16 service_id,
|
|
u8 *ul_pipe, u8 *dl_pipe);
|
|
int (*get_user_msi_vector)(struct ath11k_base *ab, char *user_name,
|
|
int *num_vectors, u32 *user_base_data,
|
|
u32 *base_vector);
|
|
void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo,
|
|
u32 *msi_addr_hi);
|
|
void (*ce_irq_enable)(struct ath11k_base *ab);
|
|
void (*ce_irq_disable)(struct ath11k_base *ab);
|
|
void (*get_ce_msi_idx)(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx);
|
|
void (*coredump_download)(struct ath11k_base *ab);
|
|
};
|
|
|
|
static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
|
|
{
|
|
if (ab->hif.ops->ce_irq_enable)
|
|
ab->hif.ops->ce_irq_enable(ab);
|
|
}
|
|
|
|
static inline void ath11k_hif_ce_irq_disable(struct ath11k_base *ab)
|
|
{
|
|
if (ab->hif.ops->ce_irq_disable)
|
|
ab->hif.ops->ce_irq_disable(ab);
|
|
}
|
|
|
|
static inline int ath11k_hif_start(struct ath11k_base *ab)
|
|
{
|
|
return ab->hif.ops->start(ab);
|
|
}
|
|
|
|
static inline void ath11k_hif_stop(struct ath11k_base *ab)
|
|
{
|
|
ab->hif.ops->stop(ab);
|
|
}
|
|
|
|
static inline void ath11k_hif_irq_enable(struct ath11k_base *ab)
|
|
{
|
|
ab->hif.ops->irq_enable(ab);
|
|
}
|
|
|
|
static inline void ath11k_hif_irq_disable(struct ath11k_base *ab)
|
|
{
|
|
ab->hif.ops->irq_disable(ab);
|
|
}
|
|
|
|
static inline int ath11k_hif_power_up(struct ath11k_base *ab)
|
|
{
|
|
if (!ab->hif.ops->power_up)
|
|
return -EOPNOTSUPP;
|
|
|
|
return ab->hif.ops->power_up(ab);
|
|
}
|
|
|
|
static inline void ath11k_hif_power_down(struct ath11k_base *ab, bool is_suspend)
|
|
{
|
|
if (!ab->hif.ops->power_down)
|
|
return;
|
|
|
|
ab->hif.ops->power_down(ab, is_suspend);
|
|
}
|
|
|
|
static inline int ath11k_hif_suspend(struct ath11k_base *ab)
|
|
{
|
|
if (ab->hif.ops->suspend)
|
|
return ab->hif.ops->suspend(ab);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int ath11k_hif_resume(struct ath11k_base *ab)
|
|
{
|
|
if (ab->hif.ops->resume)
|
|
return ab->hif.ops->resume(ab);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline u32 ath11k_hif_read32(struct ath11k_base *ab, u32 address)
|
|
{
|
|
return ab->hif.ops->read32(ab, address);
|
|
}
|
|
|
|
static inline void ath11k_hif_write32(struct ath11k_base *ab, u32 address, u32 data)
|
|
{
|
|
ab->hif.ops->write32(ab, address, data);
|
|
}
|
|
|
|
static inline int ath11k_hif_read(struct ath11k_base *ab, void *buf,
|
|
u32 start, u32 end)
|
|
{
|
|
if (!ab->hif.ops->read)
|
|
return -EOPNOTSUPP;
|
|
|
|
return ab->hif.ops->read(ab, buf, start, end);
|
|
}
|
|
|
|
static inline int ath11k_hif_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
|
|
u8 *ul_pipe, u8 *dl_pipe)
|
|
{
|
|
return ab->hif.ops->map_service_to_pipe(ab, service_id, ul_pipe, dl_pipe);
|
|
}
|
|
|
|
static inline int ath11k_get_user_msi_vector(struct ath11k_base *ab, char *user_name,
|
|
int *num_vectors, u32 *user_base_data,
|
|
u32 *base_vector)
|
|
{
|
|
if (!ab->hif.ops->get_user_msi_vector)
|
|
return -EOPNOTSUPP;
|
|
|
|
return ab->hif.ops->get_user_msi_vector(ab, user_name, num_vectors,
|
|
user_base_data,
|
|
base_vector);
|
|
}
|
|
|
|
static inline void ath11k_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
|
|
u32 *msi_addr_hi)
|
|
{
|
|
if (!ab->hif.ops->get_msi_address)
|
|
return;
|
|
|
|
ab->hif.ops->get_msi_address(ab, msi_addr_lo, msi_addr_hi);
|
|
}
|
|
|
|
static inline void ath11k_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
|
|
u32 *msi_data_idx)
|
|
{
|
|
if (ab->hif.ops->get_ce_msi_idx)
|
|
ab->hif.ops->get_ce_msi_idx(ab, ce_id, msi_data_idx);
|
|
else
|
|
*msi_data_idx = ce_id;
|
|
}
|
|
|
|
static inline void ath11k_hif_coredump_download(struct ath11k_base *ab)
|
|
{
|
|
if (ab->hif.ops->coredump_download)
|
|
ab->hif.ops->coredump_download(ab);
|
|
}
|
|
|
|
#endif /* _HIF_H_ */
|