Ver Fonte

qcacmn: update the hang data for htc

whenever there is a wmi command timeout and recovery is triggered,
the htc credit history gives insight into whether host had the credits
to send the command to firmware. Add the credit history from the
htc module.

Change-Id: Iaa760981296862f8af496a23e3c24bc2fda0fb55
CRs-Fixed: 2651744
Arun Kumar Khandavalli há 5 anos atrás
pai
commit
1f76b82659
5 ficheiros alterados com 180 adições e 3 exclusões
  1. 4 0
      htc/htc.c
  2. 61 1
      htc/htc_credit_history.c
  3. 19 2
      htc/htc_credit_history.h
  4. 44 0
      htc/htc_hang_event.c
  5. 52 0
      htc/htc_hang_event.h

+ 4 - 0
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 <hif.h>
 #include <qdf_nbuf.h>           /* qdf_nbuf_t */
 #include <qdf_types.h>          /* 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);

+ 61 - 1
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 <qdf_lock.h>
+#include <qdf_hang_event_notifier.h>
+#include <qdf_notifier.h>
 
 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

+ 19 - 2
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

+ 44 - 0
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 <qdf_hang_event_notifier.h>
+#include <qdf_notifier.h>
+#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);
+}

+ 52 - 0
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