xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_credit_history.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2018,2020-2021 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_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_deinit(void)
64 {
65 	qdf_minidump_remove(&htc_credit_history_buffer,
66 			    sizeof(htc_credit_history_buffer), "htc_credit");
67 }
68 void htc_credit_history_init(void)
69 {
70 	qdf_spinlock_create(&g_htc_credit_lock);
71 	g_htc_credit_history_idx = 0;
72 	g_htc_credit_history_length = 0;
73 	qdf_minidump_log(&htc_credit_history_buffer,
74 			 sizeof(htc_credit_history_buffer), "htc_credit");
75 }
76 
77 /**
78  * htc_credit_record() - records tx que state & credit transactions
79  * @type:		type of echange can be HTC_REQUEST_CREDIT
80  *			or HTC_PROCESS_CREDIT_REPORT
81  * @tx_credits:		current number of tx_credits
82  * @htc_tx_queue_depth:	current hct tx queue depth
83  *
84  * This function records the credits and pending commands whenever a command is
85  * sent or credits are returned.  Call this after the credits have been updated
86  * according to the transaction.  Call this before dequeing commands.
87  *
88  * Consider making this function accept an HTC_ENDPOINT and find the current
89  * credits and queue depth itself.
90  *
91  */
92 void htc_credit_record(enum htc_credit_exchange_type type, uint32_t tx_credit,
93 		       uint32_t htc_tx_queue_depth)
94 {
95 	qdf_spin_lock_bh(&g_htc_credit_lock);
96 	if (g_htc_credit_history_idx >= HTC_CREDIT_HISTORY_MAX)
97 		g_htc_credit_history_idx = 0;
98 
99 	htc_credit_history_buffer[g_htc_credit_history_idx].type = type;
100 	htc_credit_history_buffer[g_htc_credit_history_idx].time =
101 		qdf_get_log_timestamp();
102 	htc_credit_history_buffer[g_htc_credit_history_idx].tx_credit =
103 		tx_credit;
104 	htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth =
105 		htc_tx_queue_depth;
106 
107 	g_htc_credit_history_idx++;
108 	g_htc_credit_history_length++;
109 	htc_add_emulation_delay();
110 	qdf_spin_unlock_bh(&g_htc_credit_lock);
111 }
112 
113 void htc_print_credit_history(HTC_HANDLE htc, uint32_t count,
114 			      qdf_abstract_print *print, void *print_priv)
115 {
116 	uint32_t idx;
117 
118 	print(print_priv, "HTC Credit History (count %u)", count);
119 	qdf_spin_lock_bh(&g_htc_credit_lock);
120 
121 	if (count > HTC_CREDIT_HISTORY_MAX)
122 		count = HTC_CREDIT_HISTORY_MAX;
123 	if (count > g_htc_credit_history_length)
124 		count = g_htc_credit_history_length;
125 
126 	/* subtract count from index, and wrap if necessary */
127 	idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count;
128 	idx %= HTC_CREDIT_HISTORY_MAX;
129 
130 	print(print_priv,
131 	      "Time (seconds)     Type                         Credits    Queue Depth");
132 	while (count) {
133 		struct HTC_CREDIT_HISTORY *hist =
134 						&htc_credit_history_buffer[idx];
135 		uint64_t secs, usecs;
136 
137 		qdf_log_timestamp_to_secs(hist->time, &secs, &usecs);
138 		print(print_priv, "% 8lld.%06lld    %-25s    %-7.d    %d",
139 		      secs,
140 		      usecs,
141 		      htc_credit_exchange_type_str(hist->type),
142 		      hist->tx_credit,
143 		      hist->htc_tx_queue_depth);
144 
145 		--count;
146 		++idx;
147 		if (idx >= HTC_CREDIT_HISTORY_MAX)
148 			idx = 0;
149 	}
150 
151 	qdf_spin_unlock_bh(&g_htc_credit_lock);
152 }
153 
154 #ifdef WLAN_HANG_EVENT
155 void htc_log_hang_credit_history(struct notifier_block *block, void *data)
156 {
157 	qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block,
158 							notif_block);
159 	struct qdf_notifer_data *htc_hang_data = data;
160 	uint32_t count = NUM_HANG_CREDIT_HISTORY, idx, total_len;
161 	HTC_HANDLE htc;
162 	struct htc_hang_data_fixed_param *cmd;
163 	uint8_t *htc_buf_ptr;
164 
165 	htc = notif_block->priv_data;
166 
167 	if (!htc)
168 		return;
169 
170 	if (!htc_hang_data)
171 		return;
172 
173 	total_len = sizeof(struct htc_hang_data_fixed_param);
174 	qdf_spin_lock_bh(&g_htc_credit_lock);
175 
176 	if (count > HTC_CREDIT_HISTORY_MAX)
177 		count = HTC_CREDIT_HISTORY_MAX;
178 	if (count > g_htc_credit_history_length)
179 		count = g_htc_credit_history_length;
180 
181 	idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count;
182 	idx %= HTC_CREDIT_HISTORY_MAX;
183 
184 	qdf_spin_unlock_bh(&g_htc_credit_lock);
185 
186 	while (count) {
187 		struct HTC_CREDIT_HISTORY *hist =
188 						&htc_credit_history_buffer[idx];
189 		htc_buf_ptr = htc_hang_data->hang_data + htc_hang_data->offset;
190 		cmd = (struct htc_hang_data_fixed_param *)htc_buf_ptr;
191 
192 		if (htc_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET)
193 			return;
194 
195 		QDF_HANG_EVT_SET_HDR(&cmd->tlv_header,
196 				     HANG_EVT_TAG_HTC_CREDIT_HIST,
197 		QDF_HANG_GET_STRUCT_TLVLEN(struct htc_hang_data_fixed_param));
198 		qdf_mem_copy(&cmd->credit_hist, hist, sizeof(*hist));
199 		--count;
200 		++idx;
201 		if (idx >= HTC_CREDIT_HISTORY_MAX)
202 			idx = 0;
203 		htc_hang_data->offset += total_len;
204 	}
205 }
206 #endif
207