diff --git a/htc/htc.c b/htc/htc.c index cb34eab817..0bff8117fb 100644 --- a/htc/htc.c +++ b/htc/htc.c @@ -19,6 +19,7 @@ #include "htc_debug.h" #include "htc_internal.h" #include "htc_credit_history.h" +#include "htc_hang_event.h" #include #include /* qdf_nbuf_t */ #include /* qdf_print */ @@ -380,6 +381,8 @@ HTC_HANDLE htc_create(void *ol_sc, struct htc_init_info *pInfo, HTC_TRACE("-htc_create: (0x%pK)", target); + htc_hang_event_notifier_register(target); + return (HTC_HANDLE) target; } @@ -389,6 +392,7 @@ void htc_destroy(HTC_HANDLE HTCHandle) AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_destroy .. Destroying :0x%pK\n", target)); + htc_hang_event_notifier_unregister(); hif_stop(htc_get_hif_device(HTCHandle)); if (target) htc_cleanup(target); diff --git a/htc/htc_credit_history.c b/htc/htc_credit_history.c index 4e06720123..76ad4f12c1 100644 --- a/htc/htc_credit_history.c +++ b/htc/htc_credit_history.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 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 @@ -20,6 +20,8 @@ #include "htc_internal.h" #include "htc_credit_history.h" #include +#include +#include struct HTC_CREDIT_HISTORY { enum htc_credit_exchange_type type; @@ -28,6 +30,11 @@ struct HTC_CREDIT_HISTORY { uint32_t htc_tx_queue_depth; }; +struct htc_hang_data_fixed_param { + uint32_t tlv_header; + struct HTC_CREDIT_HISTORY credit_hist; +} qdf_packed; + static qdf_spinlock_t g_htc_credit_lock; static uint32_t g_htc_credit_history_idx; static uint32_t g_htc_credit_history_length; @@ -135,3 +142,56 @@ void htc_print_credit_history(HTC_HANDLE htc, uint32_t count, qdf_spin_unlock_bh(&g_htc_credit_lock); } + +#ifdef WLAN_HANG_EVENT +void htc_log_hang_credit_history(struct notifier_block *block, void *data) +{ + qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block, + notif_block); + struct qdf_notifer_data *htc_hang_data = data; + uint32_t count = 3, idx, total_len; + HTC_HANDLE htc; + struct htc_hang_data_fixed_param *cmd; + uint8_t *htc_buf_ptr; + + htc = notif_block->priv_data; + + if (!htc) + return; + + 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); + + if (count > HTC_CREDIT_HISTORY_MAX) + count = HTC_CREDIT_HISTORY_MAX; + if (count > g_htc_credit_history_length) + count = g_htc_credit_history_length; + + idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count; + idx %= HTC_CREDIT_HISTORY_MAX; + + qdf_spin_unlock_bh(&g_htc_credit_lock); + + while (count) { + struct HTC_CREDIT_HISTORY *hist = + &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; + 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)); + qdf_mem_copy(&cmd->credit_hist, hist, sizeof(*hist)); + --count; + ++idx; + if (idx >= HTC_CREDIT_HISTORY_MAX) + idx = 0; + htc_hang_data->offset += total_len; + } +} +#endif diff --git a/htc/htc_credit_history.h b/htc/htc_credit_history.h index 78b284eaac..bd02c998a1 100644 --- a/htc/htc_credit_history.h +++ b/htc/htc_credit_history.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 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 @@ -32,7 +32,24 @@ void htc_credit_history_init(void); void htc_credit_record(enum htc_credit_exchange_type type, uint32_t tx_credit, uint32_t htc_tx_queue_depth); - +#ifdef WLAN_HANG_EVENT +/** + * htc_log_hang_credit_history: Log the credit history into a buffer + * @block: Notifier block + * @data: Private data of the block. + * + * HTC hang event notifier callback inovked when the recovery is triggered + * to log the credit information to understand the reason for recovery. + * + * Return: none + */ +void htc_log_hang_credit_history(struct notifier_block *block, void *data); +#else +static inline +void htc_log_hang_credit_history(struct notifier_block *block, void *data) +{ +} +#endif #else /* FEATURE_HTC_CREDIT_HISTORY */ static inline diff --git a/htc/htc_hang_event.c b/htc/htc_hang_event.c new file mode 100644 index 0000000000..b6b75760dc --- /dev/null +++ b/htc/htc_hang_event.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include "htc_hang_event.h" +#include "htc_internal.h" +#include "htc_credit_history.h" + +static int htc_recovery_notifier_call(struct notifier_block *block, + unsigned long state, + void *data) +{ + htc_log_hang_credit_history(block, data); + + return NOTIFY_OK; +} + +static qdf_notif_block htc_recovery_notifier = { + .notif_block.notifier_call = htc_recovery_notifier_call, +}; + +QDF_STATUS htc_hang_event_notifier_register(HTC_TARGET *target) +{ + htc_recovery_notifier.priv_data = target; + return qdf_hang_event_register_notifier(&htc_recovery_notifier); +} + +QDF_STATUS htc_hang_event_notifier_unregister(void) +{ + return qdf_hang_event_unregister_notifier(&htc_recovery_notifier); +} diff --git a/htc/htc_hang_event.h b/htc/htc_hang_event.h new file mode 100644 index 0000000000..3304541bca --- /dev/null +++ b/htc/htc_hang_event.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef HTC_HANG_EVENT_H +#define HTC_HANG_EVENT_H + +#include "htc_internal.h" + +#ifdef WLAN_HANG_EVENT +/** + * htc_hang_event_notifier_register() - HTC hang event notifier register + * @target: Target specific htc hangle + * + * This function registers htc layer notifier for the hang event notifier chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS htc_hang_event_notifier_register(HTC_TARGET *target); + +/** + * htc_hang_event_notifier_unregister() - htc hang event notifier unregister + * + * This function unregisters htc layer notifier for the hang event notifier + * chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS htc_hang_event_notifier_unregister(void); +#else +static inline QDF_STATUS htc_hang_event_notifier_register(HTC_TARGET *target) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS htc_hang_event_notifier_unregister(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif