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

In case of firmware assert snapshot of firmware memory is essential for debugging. Add firmware coredump collection support for PCI bus. Collect RDDM and firmware paging dumps from MHI and pack them in TLV format and also pack various memory shared during QMI phase in separate TLVs. Add necessary header and share the dumps to user space using dev coredump framework. Coredump collection is disabled by default and can be enabled using menuconfig. Dump collected for a radio is 55 MB approximately. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.2.1-00201-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com> Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com> Link: https://patch.msgid.link/20240717085604.4131642-1-quic_ssreeela@quicinc.com Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
165 lines
4.2 KiB
C
165 lines
4.2 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
|
/*
|
|
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#ifndef ATH12K_HIF_H
|
|
#define ATH12K_HIF_H
|
|
|
|
#include "core.h"
|
|
|
|
struct ath12k_hif_ops {
|
|
u32 (*read32)(struct ath12k_base *ab, u32 address);
|
|
void (*write32)(struct ath12k_base *ab, u32 address, u32 data);
|
|
void (*irq_enable)(struct ath12k_base *ab);
|
|
void (*irq_disable)(struct ath12k_base *ab);
|
|
int (*start)(struct ath12k_base *ab);
|
|
void (*stop)(struct ath12k_base *ab);
|
|
int (*power_up)(struct ath12k_base *ab);
|
|
void (*power_down)(struct ath12k_base *ab, bool is_suspend);
|
|
int (*suspend)(struct ath12k_base *ab);
|
|
int (*resume)(struct ath12k_base *ab);
|
|
int (*map_service_to_pipe)(struct ath12k_base *ab, u16 service_id,
|
|
u8 *ul_pipe, u8 *dl_pipe);
|
|
int (*get_user_msi_vector)(struct ath12k_base *ab, char *user_name,
|
|
int *num_vectors, u32 *user_base_data,
|
|
u32 *base_vector);
|
|
void (*get_msi_address)(struct ath12k_base *ab, u32 *msi_addr_lo,
|
|
u32 *msi_addr_hi);
|
|
void (*ce_irq_enable)(struct ath12k_base *ab);
|
|
void (*ce_irq_disable)(struct ath12k_base *ab);
|
|
void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx);
|
|
int (*panic_handler)(struct ath12k_base *ab);
|
|
void (*coredump_download)(struct ath12k_base *ab);
|
|
};
|
|
|
|
static inline int ath12k_hif_map_service_to_pipe(struct ath12k_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 ath12k_hif_get_user_msi_vector(struct ath12k_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 ath12k_hif_get_msi_address(struct ath12k_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 ath12k_hif_get_ce_msi_idx(struct ath12k_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 ath12k_hif_ce_irq_enable(struct ath12k_base *ab)
|
|
{
|
|
if (ab->hif.ops->ce_irq_enable)
|
|
ab->hif.ops->ce_irq_enable(ab);
|
|
}
|
|
|
|
static inline void ath12k_hif_ce_irq_disable(struct ath12k_base *ab)
|
|
{
|
|
if (ab->hif.ops->ce_irq_disable)
|
|
ab->hif.ops->ce_irq_disable(ab);
|
|
}
|
|
|
|
static inline void ath12k_hif_irq_enable(struct ath12k_base *ab)
|
|
{
|
|
ab->hif.ops->irq_enable(ab);
|
|
}
|
|
|
|
static inline void ath12k_hif_irq_disable(struct ath12k_base *ab)
|
|
{
|
|
ab->hif.ops->irq_disable(ab);
|
|
}
|
|
|
|
static inline int ath12k_hif_suspend(struct ath12k_base *ab)
|
|
{
|
|
if (ab->hif.ops->suspend)
|
|
return ab->hif.ops->suspend(ab);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int ath12k_hif_resume(struct ath12k_base *ab)
|
|
{
|
|
if (ab->hif.ops->resume)
|
|
return ab->hif.ops->resume(ab);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int ath12k_hif_start(struct ath12k_base *ab)
|
|
{
|
|
return ab->hif.ops->start(ab);
|
|
}
|
|
|
|
static inline void ath12k_hif_stop(struct ath12k_base *ab)
|
|
{
|
|
ab->hif.ops->stop(ab);
|
|
}
|
|
|
|
static inline u32 ath12k_hif_read32(struct ath12k_base *ab, u32 address)
|
|
{
|
|
return ab->hif.ops->read32(ab, address);
|
|
}
|
|
|
|
static inline void ath12k_hif_write32(struct ath12k_base *ab, u32 address,
|
|
u32 data)
|
|
{
|
|
ab->hif.ops->write32(ab, address, data);
|
|
}
|
|
|
|
static inline int ath12k_hif_power_up(struct ath12k_base *ab)
|
|
{
|
|
if (!ab->hif.ops->power_up)
|
|
return -EOPNOTSUPP;
|
|
|
|
return ab->hif.ops->power_up(ab);
|
|
}
|
|
|
|
static inline void ath12k_hif_power_down(struct ath12k_base *ab, bool is_suspend)
|
|
{
|
|
if (!ab->hif.ops->power_down)
|
|
return;
|
|
|
|
ab->hif.ops->power_down(ab, is_suspend);
|
|
}
|
|
|
|
static inline int ath12k_hif_panic_handler(struct ath12k_base *ab)
|
|
{
|
|
if (!ab->hif.ops->panic_handler)
|
|
return NOTIFY_DONE;
|
|
|
|
return ab->hif.ops->panic_handler(ab);
|
|
}
|
|
|
|
static inline void ath12k_hif_coredump_download(struct ath12k_base *ab)
|
|
{
|
|
if (ab->hif.ops->coredump_download)
|
|
ab->hif.ops->coredump_download(ab);
|
|
}
|
|
#endif /* ATH12K_HIF_H */
|