xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_credit_history.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "htc_debug.h"
20 #include "htc_internal.h"
21 #include "htc_credit_history.h"
22 #include <qdf_lock.h>
23 #include <qdf_hang_event_notifier.h>
24 #include <qdf_notifier.h>
25 
26 struct HTC_CREDIT_HISTORY {
27 	enum htc_credit_exchange_type type;
28 	uint64_t time;
29 	uint32_t tx_credit;
30 	uint32_t htc_tx_queue_depth;
31 };
32 
33 struct htc_hang_data_fixed_param {
34 	uint16_t tlv_header;
35 	struct HTC_CREDIT_HISTORY credit_hist;
36 } qdf_packed;
37 
38 static qdf_spinlock_t g_htc_credit_lock;
39 static uint32_t g_htc_credit_history_idx;
40 static uint32_t g_htc_credit_history_length;
41 static
42 struct HTC_CREDIT_HISTORY htc_credit_history_buffer[HTC_CREDIT_HISTORY_MAX];
43 
44 #define NUM_HANG_CREDIT_HISTORY 1
45 
46 #ifdef QCA_WIFI_NAPIER_EMULATION
47 #define HTC_EMULATION_DELAY_IN_MS 20
48 /**
49  * htc_add_delay(): Adds a delay in before proceeding, only for emulation
50  *
51  * Return: None
52  */
53 static inline void htc_add_emulation_delay(void)
54 {
55 	qdf_mdelay(HTC_EMULATION_DELAY_IN_MS);
56 }
57 #else
58 static inline void htc_add_emulation_delay(void)
59 {
60 }
61 #endif
62 
63 void htc_credit_history_init(void)
64 {
65 	qdf_spinlock_create(&g_htc_credit_lock);
66 	g_htc_credit_history_idx = 0;
67 	g_htc_credit_history_length = 0;
68 }
69 
70 /**
71  * htc_credit_record() - records tx que state & credit transactions
72  * @type:		type of echange can be HTC_REQUEST_CREDIT
73  *			or HTC_PROCESS_CREDIT_REPORT
74  * @tx_credits:		current number of tx_credits
75  * @htc_tx_queue_depth:	current hct tx queue depth
76  *
77  * This function records the credits and pending commands whenever a command is
78  * sent or credits are returned.  Call this after the credits have been updated
79  * according to the transaction.  Call this before dequeing commands.
80  *
81  * Consider making this function accept an HTC_ENDPOINT and find the current
82  * credits and queue depth itself.
83  *
84  */
85 void htc_credit_record(enum htc_credit_exchange_type type, uint32_t tx_credit,
86 		       uint32_t htc_tx_queue_depth)
87 {
88 	qdf_spin_lock_bh(&g_htc_credit_lock);
89 	if (g_htc_credit_history_idx >= HTC_CREDIT_HISTORY_MAX)
90 		g_htc_credit_history_idx = 0;
91 
92 	htc_credit_history_buffer[g_htc_credit_history_idx].type = type;
93 	htc_credit_history_buffer[g_htc_credit_history_idx].time =
94 		qdf_get_log_timestamp();
95 	htc_credit_history_buffer[g_htc_credit_history_idx].tx_credit =
96 		tx_credit;
97 	htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth =
98 		htc_tx_queue_depth;
99 
100 	g_htc_credit_history_idx++;
101 	g_htc_credit_history_length++;
102 	htc_add_emulation_delay();
103 	qdf_spin_unlock_bh(&g_htc_credit_lock);
104 }
105 
106 void htc_print_credit_history(HTC_HANDLE htc, uint32_t count,
107 			      qdf_abstract_print *print, void *print_priv)
108 {
109 	uint32_t idx;
110 
111 	print(print_priv, "HTC Credit History (count %u)", count);
112 	qdf_spin_lock_bh(&g_htc_credit_lock);
113 
114 	if (count > HTC_CREDIT_HISTORY_MAX)
115 		count = HTC_CREDIT_HISTORY_MAX;
116 	if (count > g_htc_credit_history_length)
117 		count = g_htc_credit_history_length;
118 
119 	/* subtract count from index, and wrap if necessary */
120 	idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count;
121 	idx %= HTC_CREDIT_HISTORY_MAX;
122 
123 	print(print_priv,
124 	      "Time (seconds)     Type                         Credits    Queue Depth");
125 	while (count) {
126 		struct HTC_CREDIT_HISTORY *hist =
127 						&htc_credit_history_buffer[idx];
128 		uint64_t secs, usecs;
129 
130 		qdf_log_timestamp_to_secs(hist->time, &secs, &usecs);
131 		print(print_priv, "% 8lld.%06lld    %-25s    %-7.d    %d",
132 		      secs,
133 		      usecs,
134 		      htc_credit_exchange_type_str(hist->type),
135 		      hist->tx_credit,
136 		      hist->htc_tx_queue_depth);
137 
138 		--count;
139 		++idx;
140 		if (idx >= HTC_CREDIT_HISTORY_MAX)
141 			idx = 0;
142 	}
143 
144 	qdf_spin_unlock_bh(&g_htc_credit_lock);
145 }
146 
147 #ifdef WLAN_HANG_EVENT
148 void htc_log_hang_credit_history(struct notifier_block *block, void *data)
149 {
150 	qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block,
151 							notif_block);
152 	struct qdf_notifer_data *htc_hang_data = data;
153 	uint32_t count = NUM_HANG_CREDIT_HISTORY, idx, total_len;
154 	HTC_HANDLE htc;
155 	struct htc_hang_data_fixed_param *cmd;
156 	uint8_t *htc_buf_ptr;
157 
158 	htc = notif_block->priv_data;
159 
160 	if (!htc)
161 		return;
162 
163 	if (!htc_hang_data)
164 		return;
165 
166 	total_len = sizeof(struct htc_hang_data_fixed_param);
167 	qdf_spin_lock_bh(&g_htc_credit_lock);
168 
169 	if (count > HTC_CREDIT_HISTORY_MAX)
170 		count = HTC_CREDIT_HISTORY_MAX;
171 	if (count > g_htc_credit_history_length)
172 		count = g_htc_credit_history_length;
173 
174 	idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count;
175 	idx %= HTC_CREDIT_HISTORY_MAX;
176 
177 	qdf_spin_unlock_bh(&g_htc_credit_lock);
178 
179 	while (count) {
180 		struct HTC_CREDIT_HISTORY *hist =
181 						&htc_credit_history_buffer[idx];
182 		htc_buf_ptr = htc_hang_data->hang_data + htc_hang_data->offset;
183 		cmd = (struct htc_hang_data_fixed_param *)htc_buf_ptr;
184 
185 		if (htc_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET)
186 			return;
187 
188 		QDF_HANG_EVT_SET_HDR(&cmd->tlv_header,
189 				     HANG_EVT_TAG_HTC_CREDIT_HIST,
190 		QDF_HANG_GET_STRUCT_TLVLEN(struct htc_hang_data_fixed_param));
191 		qdf_mem_copy(&cmd->credit_hist, hist, sizeof(*hist));
192 		--count;
193 		++idx;
194 		if (idx >= HTC_CREDIT_HISTORY_MAX)
195 			idx = 0;
196 		htc_hang_data->offset += total_len;
197 	}
198 }
199 #endif
200