From 4be28ba641e38b735af7f49038d34751dd8beacd Mon Sep 17 00:00:00 2001 From: Kai Liu Date: Tue, 20 Oct 2020 22:22:39 +0800 Subject: [PATCH] qcacmn: Enhance hang info feature Add bus related info in hif layer in order to get bus status when hang issue happened. Change-Id: If922e0892e0f65de778b9696bbc56fc63c25c169 CRs-Fixed: 2801350 --- hif/src/ce/ce_main.c | 3 +++ hif/src/dispatcher/dummy.c | 13 +++++++++++++ hif/src/dispatcher/dummy.h | 2 ++ hif/src/dispatcher/multibus.c | 9 +++++++++ hif/src/dispatcher/multibus.h | 21 +++++++++++++++++++++ hif/src/dispatcher/multibus_ahb.c | 2 ++ hif/src/dispatcher/multibus_ipci.c | 1 + hif/src/dispatcher/multibus_pci.c | 2 ++ hif/src/dispatcher/multibus_sdio.c | 3 ++- hif/src/dispatcher/multibus_snoc.c | 1 + hif/src/dispatcher/multibus_usb.c | 3 ++- hif/src/hif_main.c | 4 +++- hif/src/pcie/if_pci.c | 28 ++++++++++++++++++++++++++++ hif/src/pcie/if_pci.h | 15 +++++++++++++++ htc/htc_credit_history.c | 7 ++++--- qdf/inc/qdf_hang_event_notifier.h | 6 ++++-- qdf/inc/qdf_types.h | 2 ++ wmi/src/wmi_hang_event.c | 6 +++--- 18 files changed, 117 insertions(+), 11 deletions(-) diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index 2c6fbe6ff0..22654c81cb 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -4486,6 +4486,9 @@ void hif_log_ce_info(struct hif_softc *scn, uint8_t *data, size = sizeof(info) - (CE_COUNT_MAX - info.ce_count) * sizeof(struct ce_index); + if (*offset + size > QDF_WLAN_HANG_FW_OFFSET) + return; + QDF_HANG_EVT_SET_HDR(&info.tlv_header, HANG_EVT_TAG_CE_INFO, size - QDF_HANG_EVENT_TLV_HDR_SIZE); diff --git a/hif/src/dispatcher/dummy.c b/hif/src/dispatcher/dummy.c index e226819b1a..1f78442b00 100644 --- a/hif/src/dispatcher/dummy.c +++ b/hif/src/dispatcher/dummy.c @@ -387,3 +387,16 @@ int hif_dummy_config_irq_by_ceid(struct hif_softc *scn, int ce_id) { return 0; } + +/** + * hif_dummy_log_bus_info - dummy call + * @scn: hif context + * @data: hang event data buffer + * @offset: offset at which data needs to be written + * + * Return: None + */ +void hif_dummy_log_bus_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset) +{ +} diff --git a/hif/src/dispatcher/dummy.h b/hif/src/dispatcher/dummy.h index f580caf881..50eee2d140 100644 --- a/hif/src/dispatcher/dummy.h +++ b/hif/src/dispatcher/dummy.h @@ -61,3 +61,5 @@ int hif_dummy_map_ce_to_irq(struct hif_softc *scn, int ce_id); int hif_dummy_addr_in_boundary(struct hif_softc *scn, uint32_t offset); void hif_dummy_config_irq_affinity(struct hif_softc *scn); int hif_dummy_config_irq_by_ceid(struct hif_softc *scn, int ce_id); +void hif_dummy_log_bus_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset); diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c index 50c6c9af27..f7d5ea6283 100644 --- a/hif/src/dispatcher/multibus.c +++ b/hif/src/dispatcher/multibus.c @@ -574,3 +574,12 @@ int hif_config_irq_by_ceid(struct hif_softc *hif_sc, int ce_id) { return hif_sc->bus_ops.hif_config_irq_by_ceid(hif_sc, ce_id); } + +#ifdef HIF_BUS_LOG_INFO +void hif_log_bus_info(struct hif_softc *hif_sc, uint8_t *data, + unsigned int *offset) +{ + if (hif_sc->bus_ops.hif_log_bus_info) + hif_sc->bus_ops.hif_log_bus_info(hif_sc, data, offset); +} +#endif diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h index 9ae40367b0..1ebe463159 100644 --- a/hif/src/dispatcher/multibus.h +++ b/hif/src/dispatcher/multibus.h @@ -87,6 +87,8 @@ struct hif_bus_ops { bool (*hif_needs_bmi)(struct hif_softc *hif_sc); void (*hif_config_irq_affinity)(struct hif_softc *hif_sc); int (*hif_config_irq_by_ceid)(struct hif_softc *hif_sc, int ce_id); + void (*hif_log_bus_info)(struct hif_softc *scn, uint8_t *data, + unsigned int *offset); }; #ifdef HIF_SNOC @@ -264,4 +266,23 @@ void hif_config_irq_affinity(struct hif_softc *hif_sc); * Return: 0 on success, negative value on error. */ int hif_config_irq_by_ceid(struct hif_softc *hif_sc, int ce_id); + +#ifdef HIF_BUS_LOG_INFO +/** + * hif_log_bus_info() - API to log bus related info + * @scn: hif handle + * @data: hang event data buffer + * @offset: offset at which data needs to be written + * + * Return: None + */ +void hif_log_bus_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset); +#else +static inline +void hif_log_bus_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset) +{ +} +#endif #endif /* _MULTIBUS_H_ */ diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c index 19c13d2df5..2977a57d49 100644 --- a/hif/src/dispatcher/multibus_ahb.c +++ b/hif/src/dispatcher/multibus_ahb.c @@ -74,6 +74,8 @@ QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops) bus_ops->hif_config_irq_affinity = &hif_dummy_config_irq_affinity; bus_ops->hif_config_irq_by_ceid = &hif_ahb_configure_irq_by_ceid; + bus_ops->hif_log_bus_info = &hif_dummy_log_bus_info; + return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_ipci.c b/hif/src/dispatcher/multibus_ipci.c index 48da71a46f..4eedae6e4c 100644 --- a/hif/src/dispatcher/multibus_ipci.c +++ b/hif/src/dispatcher/multibus_ipci.c @@ -78,6 +78,7 @@ QDF_STATUS hif_initialize_ipci_ops(struct hif_softc *hif_sc) bus_ops->hif_config_irq_affinity = &hif_dummy_config_irq_affinity; bus_ops->hif_config_irq_by_ceid = &hif_dummy_config_irq_by_ceid; + bus_ops->hif_log_bus_info = &hif_dummy_log_bus_info; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_pci.c b/hif/src/dispatcher/multibus_pci.c index 4783fef75e..7dd75154a2 100644 --- a/hif/src/dispatcher/multibus_pci.c +++ b/hif/src/dispatcher/multibus_pci.c @@ -92,6 +92,8 @@ QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc) bus_ops->hif_config_irq_affinity = &hif_pci_config_irq_affinity; bus_ops->hif_config_irq_by_ceid = &hif_ce_msi_configure_irq_by_ceid; + bus_ops->hif_log_bus_info = &hif_log_pcie_info; + return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_sdio.c b/hif/src/dispatcher/multibus_sdio.c index c5962a974f..97a3e194eb 100644 --- a/hif/src/dispatcher/multibus_sdio.c +++ b/hif/src/dispatcher/multibus_sdio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -66,6 +66,7 @@ QDF_STATUS hif_initialize_sdio_ops(struct hif_softc *hif_sc) &hif_dummy_disable_power_management; bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary; bus_ops->hif_needs_bmi = &hif_sdio_needs_bmi; + bus_ops->hif_log_bus_info = &hif_dummy_log_bus_info; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_snoc.c b/hif/src/dispatcher/multibus_snoc.c index f020f8e75a..d717db9833 100644 --- a/hif/src/dispatcher/multibus_snoc.c +++ b/hif/src/dispatcher/multibus_snoc.c @@ -77,6 +77,7 @@ QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *bus_ops) bus_ops->hif_needs_bmi = &hif_snoc_needs_bmi; bus_ops->hif_config_irq_affinity = &hif_dummy_config_irq_affinity; bus_ops->hif_config_irq_by_ceid = &hif_dummy_config_irq_by_ceid; + bus_ops->hif_log_bus_info = &hif_dummy_log_bus_info; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_usb.c b/hif/src/dispatcher/multibus_usb.c index e632a40134..08b08ee15a 100644 --- a/hif/src/dispatcher/multibus_usb.c +++ b/hif/src/dispatcher/multibus_usb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -67,6 +67,7 @@ QDF_STATUS hif_initialize_usb_ops(struct hif_bus_ops *bus_ops) bus_ops->hif_bus_reset_resume = &hif_usb_bus_reset_resume; bus_ops->hif_map_ce_to_irq = &hif_dummy_map_ce_to_irq; bus_ops->hif_needs_bmi = &hif_usb_needs_bmi; + bus_ops->hif_log_bus_info = &hif_dummy_log_bus_info; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index e72bf1c829..f25b49d67e 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -466,7 +466,7 @@ void hif_get_cfg_from_psoc(struct hif_softc *scn, } #endif /* WLAN_CE_INTERRUPT_THRESHOLD_CONFIG */ -#ifdef HIF_CE_LOG_INFO +#if defined(HIF_CE_LOG_INFO) || defined(HIF_BUS_LOG_INFO) /** * hif_recovery_notifier_cb - Recovery notifier callback to log * hang event data @@ -493,6 +493,8 @@ int hif_recovery_notifier_cb(struct notifier_block *block, unsigned long state, if (!hif_handle) return -EINVAL; + hif_log_bus_info(hif_handle, notif_data->hang_data, + ¬if_data->offset); hif_log_ce_info(hif_handle, notif_data->hang_data, ¬if_data->offset); diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 99739dbbaf..085eedacb7 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -54,6 +54,7 @@ #include "pci_api.h" #include "ahb_api.h" #include "wlan_cfg.h" +#include "qdf_hang_event_notifier.h" /* Maximum ms timeout for host to wake up target */ #define PCIE_WAKE_TIMEOUT 1000 @@ -2338,6 +2339,33 @@ static int __hif_check_link_status(struct hif_softc *scn) return -EACCES; } +#ifdef HIF_BUS_LOG_INFO +void hif_log_pcie_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct hang_event_bus_info info = {0}; + size_t size; + + if (!sc) { + hif_err("HIF Bus Context is Invalid"); + return; + } + + pfrm_read_config_word(sc->pdev, PCI_DEVICE_ID, &info.dev_id); + + size = sizeof(info); + QDF_HANG_EVT_SET_HDR(&info.tlv_header, HANG_EVT_TAG_BUS_INFO, + size - QDF_HANG_EVENT_TLV_HDR_SIZE); + + if (*offset + size > QDF_WLAN_HANG_FW_OFFSET) + return; + + qdf_mem_copy(data + *offset, &info, size); + *offset = *offset + size; +} +#endif + /** * hif_pci_bus_resume(): prepare hif for resume * diff --git a/hif/src/pcie/if_pci.h b/hif/src/pcie/if_pci.h index 6379fe16b1..894582e749 100644 --- a/hif/src/pcie/if_pci.h +++ b/hif/src/pcie/if_pci.h @@ -57,6 +57,11 @@ struct hif_tasklet_entry { void *hif_handler; /* struct hif_pci_softc */ }; +struct hang_event_bus_info { + uint16_t tlv_header; + uint16_t dev_id; +} qdf_packed; + /** * struct hif_msi_info - Structure to hold msi info * @magic: cookie @@ -190,4 +195,14 @@ void hif_print_pci_stats(struct hif_pci_softc *pci_scn) { } #endif /* FORCE_WAKE */ +#ifdef HIF_BUS_LOG_INFO +void hif_log_pcie_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset); +#else +static inline +void hif_log_pcie_info(struct hif_softc *scn, uint8_t *data, + unsigned int *offset) +{ +} +#endif #endif /* __ATH_PCI_H__ */ diff --git a/htc/htc_credit_history.c b/htc/htc_credit_history.c index 4f8d824b2b..de5f0bd057 100644 --- a/htc/htc_credit_history.c +++ b/htc/htc_credit_history.c @@ -163,9 +163,6 @@ void htc_log_hang_credit_history(struct notifier_block *block, void *data) if (!htc_hang_data) return; - if (htc_hang_data->offset >= QDF_WLAN_MAX_HOST_OFFSET) - return; - total_len = sizeof(struct htc_hang_data_fixed_param); qdf_spin_lock_bh(&g_htc_credit_lock); @@ -184,6 +181,10 @@ void htc_log_hang_credit_history(struct notifier_block *block, void *data) &htc_credit_history_buffer[idx]; htc_buf_ptr = htc_hang_data->hang_data + htc_hang_data->offset; cmd = (struct htc_hang_data_fixed_param *)htc_buf_ptr; + + if (htc_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET) + return; + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, HANG_EVT_TAG_HTC_CREDIT_HIST, QDF_HANG_GET_STRUCT_TLVLEN(struct htc_hang_data_fixed_param)); diff --git a/qdf/inc/qdf_hang_event_notifier.h b/qdf/inc/qdf_hang_event_notifier.h index c80ba8caa8..532ea47ca0 100644 --- a/qdf/inc/qdf_hang_event_notifier.h +++ b/qdf/inc/qdf_hang_event_notifier.h @@ -43,6 +43,7 @@ * @HANG_EVT_TAG_WMI_CMD_HIST: HTC event tag wmi command history hang event tag * @HANG_EVT_TAG_DP_PEER_INFO: DP peer info hang event tag * @HANG_EVT_TAG_CE_INFO: Copy Engine hang event tag + * @HANG_EVT_TAG_BUS_INFO: Bus hang event tag */ enum hang_event_tag { HANG_EVT_TAG_CDS, @@ -53,10 +54,11 @@ enum hang_event_tag { HANG_EVT_TAG_WMI_CMD_HIST, HANG_EVT_TAG_HTC_CREDIT_HIST, HANG_EVT_TAG_DP_PEER_INFO, - HANG_EVT_TAG_CE_INFO + HANG_EVT_TAG_CE_INFO, + HANG_EVT_TAG_BUS_INFO }; -#define QDF_HANG_EVENT_TLV_HDR_SIZE (sizeof(uint32_t)) +#define QDF_HANG_EVENT_TLV_HDR_SIZE (sizeof(uint16_t)) #define QDF_HANG_EVT_SET_HDR(tlv_buf, tag, len) \ (((uint16_t *)(tlv_buf))[0]) = (((tag) << 8) | ((len) & 0x000000FF)) diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index c3c528b415..9bf8a3c2c0 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -1345,6 +1345,7 @@ enum qdf_suspend_type { * @QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT: Peer delete all resp timeout * @QDF_WMI_BUF_SEQUENCE_MISMATCH: WMI Tx completion buffer sequence mismatch * @QDF_HAL_REG_WRITE_FAILURE: HAL register writing failures + * @QDF_SUSPEND_NO_CREDIT: host lack of credit after suspend */ enum qdf_hang_reason { QDF_REASON_UNSPECIFIED, @@ -1369,6 +1370,7 @@ enum qdf_hang_reason { QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT, QDF_WMI_BUF_SEQUENCE_MISMATCH, QDF_HAL_REG_WRITE_FAILURE, + QDF_SUSPEND_NO_CREDIT, }; /** diff --git a/wmi/src/wmi_hang_event.c b/wmi/src/wmi_hang_event.c index b23b533b07..da5af1f9ec 100644 --- a/wmi/src/wmi_hang_event.c +++ b/wmi/src/wmi_hang_event.c @@ -53,9 +53,6 @@ static void wmi_log_history(struct notifier_block *block, void *data, if (!wmi_handle) return; - if (wmi_hang_data->offset >= QDF_WLAN_MAX_HOST_OFFSET) - return; - if (wmi_history) wmi_log = &wmi_handle->log_info.wmi_event_log_buf_info; else @@ -75,6 +72,9 @@ static void wmi_log_history(struct notifier_block *block, void *data, pos = *wmi_log->p_buf_tail_idx - 1; while (nread--) { + if (wmi_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET) + return; + switch (wmi_history) { case WMI_EVT_HIST: wmi_buf_ptr = (wmi_hang_data->hang_data +